[improvement][headless-fe] Migrating scaffold version to @umi/max (#1030)

* [improvement][semantic-fe] Add model alias setting & Add view permission restrictions to the model permission management tab.
[improvement][semantic-fe] Add permission control to the action buttons for the main domain; apply high sensitivity filtering to the authorization of metrics/dimensions.
[improvement][semantic-fe] Optimize the editing mode in the dimension/metric/datasource components to use the modelId stored in the database for data, instead of relying on the data from the state manager.

* [improvement][semantic-fe] Add time granularity setting in the data source configuration.

* [improvement][semantic-fe] Dictionary import for dimension values supported in Q&A visibility

* [improvement][semantic-fe] Modification of data source creation prompt wording"

* [improvement][semantic-fe] metric market experience optimization

* [improvement][semantic-fe] enhance the analysis of metric trends

* [improvement][semantic-fe] optimize the presentation of metric trend permissions

* [improvement][semantic-fe] add metric trend download functionality

* [improvement][semantic-fe] fix the dimension initialization issue in metric correlation

* [improvement][semantic-fe] Fix the issue of database changes not taking effect when creating based on an SQL data source.

* [improvement][semantic-fe] Optimizing pagination logic and some CSS styles

* [improvement][semantic-fe] Fixing the API for the indicator list by changing "current" to "pageNum"

* [improvement][semantic-fe] Fixing the default value setting for the indicator list

* [improvement][semantic-fe] Adding batch operations for indicators/dimensions/models

* [improvement][semantic-fe] Replacing the single status update API for indicators/dimensions with a batch update API

* [improvement][semantic-fe] Redesigning the indicator homepage to incorporate trend charts and table functionality for indicators

* [improvement][semantic-fe] Optimizing the logic for setting dimension values and editing data sources, and adding system settings functionality

* [improvement][semantic-fe] Upgrading antd version to 5.x, extracting the batch operation button component, optimizing the interaction for system settings, and expanding the configuration generation types for list-to-select component.

* [improvement][semantic-fe] Adding the ability to filter dimensions based on whether they are tags or not.

* [improvement][semantic-fe] Adding the ability to edit relationships between models in the canvas.

* [improvement][semantic-fe] Updating the datePicker component to use dayjs instead.

* [improvement][semantic-fe] Fixing the issue with passing the model ID for dimensions in the indicator market.

* [improvement][semantic-fe] Fixing the abnormal state of the popup when creating a model.

* [improvement][semantic-fe] Adding permission logic for bulk operations in the indicator market.

* [improvement][semantic-fe] Adding the ability to download and transpose data.

* [improvement][semantic-fe] Fixing the initialization issue with the date selection component in the indicator details page when switching time granularity.

* [improvement][semantic-fe] Fixing the logic error in the dimension value setting.

* [improvement][semantic-fe] Fixing the synchronization issue with the question and answer settings information.

* [improvement][semantic-fe] Optimizing the canvas functionality for better performance and user experience.

* [improvement][semantic-fe] Optimizing the update process for drawing model relationship edges in the canvas.

* [improvement][semantic-fe] Changing the line type for canvas connections.

* [improvement][semantic-fe] Replacing the initialization variable from "semantic" to "headless".

* [improvement][semantic-fe] Fixing the missing migration issue for default drill-down dimension configuration in model editing. Additionally, optimizing the data retrieval method for initializing fields in the model.

* [improvement][semantic-fe] Updating the logic for the fieldName.

* [improvement][semantic-fe] Adjusting the position of the metrics tab.

* [improvement][semantic-fe] Changing the 字段名称 to 英文名称.

* [improvement][semantic-fe] Fix metric measurement deletion.

* [improvement][semantic-fe] UI optimization for metric details page.

* [improvement][semantic-fe] UI optimization for metric details page.

* [improvement][semantic-fe] UI adjustment for metric details page.

* [improvement][semantic-fe] The granularity field in the time type of model editing now supports setting it as empty.

* [improvement][semantic-fe] Added field type and metric type to the metric creation options.

* [improvement][semantic-fe] The organization structure selection feature has been added to the permission management.

* [improvement][semantic-fe] Improved user experience for the metric list.

* [improvement][semantic-fe] fix update the metric list.

* [improvement][headless-fe] Added view management functionality.

* [improvement][headless-fe] The view management functionality has been added. This feature allows users to create, edit, and manage different views within the system.

* [improvement][headless-fe] Added model editing side effect detection.

* [improvement][headless-fe] Fixed the logic error in view editing.

* [improvement][headless-fe] Fixed the issue with initializing dimension associations in metric settings.

* [improvement][headless-fe] Added the ability to hide the Q&A settings entry point.

* [improvement][headless-fe] Fixed the issue with selecting search results in metric field creation.

* [improvement][headless-fe] Added search functionality to the field list in model editing.

* [improvement][headless-fe] fix the field list in model editing

* [improvement][headless-fe] Restructured the data for the dimension value settings interface.

* [improvement][headless-fe] Added dynamic variable functionality to model creation based on SQL scripts.

* [improvement][headless-fe] Added support for passing dynamic variables as parameters in the executeSql function.

* [improvement][headless-fe] Resolved the issue where users were unable to select all options for dimensions, metrics, and fields in the metric generation process.

* [improvement][headless-fe] Replaced the term "view" with "dataset"

* [improvement][headless-fe] Added the ability to export metrics and dimensions to a specific target.

* [improvement][headless-fe] Enhanced dataset creation to support the tag mode.

* [improvement][headless-fe] Added tag value setting.

* [improvement][headless-fe] Optimized the tag setting system.

* [improvement][headless-fe] Optimized the tag setting system.

* [improvement][headless-fe] Updated the data initialization for model editing to use API requests instead.

* [improvement][headless-fe] Added search functionality to model management.

* [improvement][headless-fe] Removed field null validation during model editing.

* [improvement][headless-fe] Updated the batch operation button component.

* [improvement][headless-fe] Optimized the logic for initializing indicators in dimension value settings.

* [improvement][headless-fe] Adjusted the length of the input field for model editing names.

* [improvement][headless-fe]  Lock the version of the @ant-design/pro-table component and replace it with @ant-design/pro-components.

* [improvement][headless-fe] Optimized the style of the metrics market and tags market.

* [improvement][headless-fe] The quick creation of model fields now defaults to using the "comment" field for filling.

* [improvement][headless-fe] The quick creation of model fields now defaults to using the "comment" field for filling

* [improvement][headless-fe] The quick creation of model fields now defaults to using the "comment" field for filling.

* [improvement][headless-fe] Fixed the issue where the conditions for metric measurement creation were not being saved correctly.

* [improvement][headless-fe] Default value setting for hiding dimensions.

* [improvement][headless-fe] Updated the file imports in the project.

* [improvement][headless-fe] Adjusted the logic for displaying the tab in the theme domain.

* [improvement][headless-fe] Added term management functionality.

* [improvement][headless-fe] When creating a model, the current metric operator now allows for clearance.

* [improvement][headless-fe] Term management interface transformation

* [improvement][headless-fe] Migrating scaffold version to @umi/max
This commit is contained in:
tristanliu
2024-05-24 17:08:10 +08:00
committed by GitHub
parent 67b69768df
commit 5a332f6abf
133 changed files with 21767 additions and 31559 deletions

View File

@@ -1,19 +1,16 @@
// https://umijs.org/config/
import { defineConfig } from 'umi';
import defaultSettings, { publicPath } from './defaultSettings';
import themeSettings from './themeSettings';
import { defineConfig } from '@umijs/max';
// import { join } from 'path';
import defaultSettings from './defaultSettings';
import proxy from './proxy';
import routes from './routes';
import moment from 'moment';
import dayjs from 'dayjs';
const { REACT_APP_ENV = 'dev', RUN_TYPE } = process.env;
const publicPath = '/webapp/';
import ENV_CONFIG from './envConfig';
import CompressionWebpackPlugin from 'compression-webpack-plugin'
const { REACT_APP_ENV, RUN_TYPE } = process.env;
export default defineConfig({
webpack5: {},
mfsu: false,
define: {
// 添加这个自定义的环境变量
// 'process.env.REACT_APP_ENV': process.env.REACT_APP_ENV, // * REACT_APP_ENV 本地开发环境dev测试服test正式服prod
@@ -28,68 +25,161 @@ export default defineConfig({
metas: [
{
name: 'app_version',
content: moment().format('YYYY-MM-DD HH:mm:ss'),
content: dayjs().format('YYYY-MM-DD HH:mm:ss'),
},
],
devServer: { port: 8002 },
/**
* @name 开启 hash 模式
* @description 让 build 之后的产物包含 hash 后缀。通常用于增量发布和避免浏览器加载缓存。
* @doc https://umijs.org/docs/api/config#hash
*/
hash: true,
// history: { type: 'hash' },
antd: {},
dva: {
hmr: true,
/**
* @name 兼容性设置
* @description 设置 ie11 不一定完美兼容,需要检查自己使用的所有依赖
* @doc https://umijs.org/docs/api/config#targets
*/
// targets: {
// ie: 11,
// },
/**
* @name 路由的配置,不在路由中引入的文件不会编译
* @description 只支持 pathcomponentroutesredirectwrapperstitle 的配置
* @doc https://umijs.org/docs/guides/routes
*/
// umi routes: https://umijs.org/docs/routing
routes,
/**
* @name 主题的配置
* @description 虽然叫主题,但是其实只是 less 的变量设置
* @doc antd的主题设置 https://ant.design/docs/react/customize-theme-cn
* @doc umi 的theme 配置 https://umijs.org/docs/api/config#theme
*/
theme: {
// 如果不想要 configProvide 动态设置主题需要把这个设置为 default
// 只有设置为 variable 才能使用 configProvide 动态设置主色调
'root-entry-name': 'variable',
// 'primary-color': '#f87653',
'primary-color': '#1672fa',
},
/**
* @name Dayjs 的国际化配置
* @description 如果对国际化没有要求打开之后能减少js的包大小
* @doc https://umijs.org/docs/api/config#ignoremomentlocale
*/
ignoreMomentLocale: true,
/**
* @name 代理配置
* @description 可以让你的本地服务器代理到你的服务器上,这样你就可以访问服务器的数据了
* @see 要注意以下 代理只能在本地开发时使用build 之后就无法使用了。
* @doc 代理介绍 https://umijs.org/docs/guides/proxy
* @doc 代理配置 https://umijs.org/docs/api/config#proxy
*/
proxy: proxy[REACT_APP_ENV as keyof typeof proxy],
base: publicPath,
publicPath,
outputPath: RUN_TYPE === 'local' ? 'supersonic-webapp' : 'dist',
/**
* @name 快速热更新配置
* @description 一个不错的热更新组件,更新时可以保留 state
*/
fastRefresh: true,
//============== 以下都是max的插件配置 ===============
/**
* @name 数据流插件
* @@doc https://umijs.org/docs/max/data-flow
*/
model: {},
/**
* 一个全局的初始数据流,可以用它在插件之间共享数据
* @description 可以用来存放一些全局的数据,比如用户信息,或者一些全局的状态,全局初始状态在整个 Umi 项目的最开始创建。
* @doc https://umijs.org/docs/max/data-flow#%E5%85%A8%E5%B1%80%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81
*/
initialState: {},
/**
* @name layout 插件
* @doc https://umijs.org/docs/max/layout-menu
*/
title: 'TME内容库',
layout: {
name: '',
locale: true,
siderWidth: 208,
...defaultSettings,
},
/**
* @name moment2dayjs 插件
* @description 将项目中的 Dayjs 替换为 Dayjs
* @doc https://umijs.org/docs/max/moment2dayjs
*/
// moment2dayjs: {
// preset: 'antd',
// plugins: ['duration'],
// },
/**
* @name 国际化插件
* @doc https://umijs.org/docs/max/i18n
*/
locale: {
// default zh-CN
default: 'zh-CN',
antd: true,
// default true, when it is true, will use `navigator.language` overwrite default
baseNavigator: false,
baseNavigator: true,
},
// dynamicImport: {
// loading: '@ant-design/pro-layout/es/PageLoading',
/**
* @name antd 插件
* @description 内置了 babel import 插件
* @doc https://umijs.org/docs/max/antd#antd
*/
antd: {},
/**
* @name 网络请求配置
* @description 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。
* @doc https://umijs.org/docs/max/request
*/
request: {},
/**
* @name 权限插件
* @description 基于 initialState 的权限插件,必须先打开 initialState
* @doc https://umijs.org/docs/max/access
*/
access: {},
/**
* @name <head> 中额外的 script
* @description 配置 <head> 中额外的 script
*/
headScripts: [
// 解决首次加载时白屏的问题
{ src: '/webapp/scripts/loading.js', async: true },
],
//================ pro 插件配置 =================
presets: ['umi-presets-pro'],
/**
* @name openAPI 插件的配置
* @description 基于 openapi 的规范生成serve 和mock能减少很多样板代码
* @doc https://pro.ant.design/zh-cn/docs/openapi/
*/
// openAPI: [
// {
// requestLibPath: "import { request } from '@umijs/max'",
// // 或者使用在线的版本
// // schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json"
// schemaPath: join(__dirname, 'oneapi.json'),
// mock: false,
// },
targets: {
ie: 11,
},
// umi routes: https://umijs.org/docs/routing
routes,
// Theme for antd: https://ant.design/docs/react/customize-theme-cn
theme: {
...themeSettings,
},
alias: {
'antd/es/style': '@/assets/style',
},
esbuild: {},
title: false,
ignoreMomentLocale: true,
proxy: proxy[REACT_APP_ENV || 'dev'],
manifest: {
basePath: '/',
},
base: publicPath,
publicPath,
outputPath: RUN_TYPE === 'local' ? 'supersonic-webapp' : 'dist',
resolve: {
includes: ['src/components'],
},
chainWebpack: (config) => {
if (process.env.NODE_ENV === 'production') { // 生产模式开启
config.plugin('compression-webpack-plugin').use(
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + ['js', 'css'].join('|') + ')$'),
threshold: 10240,
minRatio: 0.6,
deleteOriginalAssets: false, // 不删除源文件
})
);
}
// {
// requestLibPath: "import { request } from '@umijs/max'",
// schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json',
// projectName: 'swagger',
// },
// ],
// 将insights-flow相关包排除出mfsu编译在pnpm link 模式下保持热更新
mfsu: {
strategy: 'normal',
// exclude: ['supersonic-insights-flow-components', 'supersonic-insights-flow-core'],
},
requestRecord: {},
exportStatic: {},
// esbuildMinifyIIFE: true,
});

View File

@@ -41,11 +41,39 @@ const ROUTES = [
envEnableList: [ENV_KEY.CHAT],
},
{
path: '/model/:domainId?/:modelId?/:menuKey?',
path: '/model/metric/edit/:metricId',
name: 'metricEdit',
hideInMenu: true,
component: './SemanticModel/Metric/Edit',
envEnableList: [ENV_KEY.SEMANTIC],
},
{
path: '/model/',
component: './SemanticModel/DomainManager',
name: 'semanticModel',
envEnableList: [ENV_KEY.SEMANTIC],
routes: [
{
path: '/model/:domainId/:modelId',
component: './SemanticModel/DomainManager',
// name: 'semanticModel',
envEnableList: [ENV_KEY.SEMANTIC],
},
{
path: '/model/:domainId/:modelId/:menuKey',
component: './SemanticModel/DomainManager',
// name: 'semanticModel',
envEnableList: [ENV_KEY.SEMANTIC],
},
],
},
// {
// path: '/model/:domainId/:modelId/:menuKey',
// component: './SemanticModel/DomainManager',
// name: 'semanticModel',
// envEnableList: [ENV_KEY.SEMANTIC],
// },
{
path: '/metric',
@@ -70,6 +98,13 @@ const ROUTES = [
component: './SemanticModel/Metric/Detail',
envEnableList: [ENV_KEY.SEMANTIC],
},
{
path: '/metric/detail/edit/:metricId',
name: 'metricDetail',
hideInMenu: true,
component: './SemanticModel/Metric/Edit',
envEnableList: [ENV_KEY.SEMANTIC],
},
],
},

View File

@@ -57,6 +57,11 @@ export const configProviderTheme = {
Radio: {
colorPrimary: '#3182ce',
},
Checkbox: {
colorPrimary: '#3182ce',
borderRadiusSM: 0,
checkboxSize: 24,
},
Table: {
headerBg: '#f9fafb',
headerColor: '#667085',

View File

@@ -4,23 +4,23 @@
"private": true,
"description": "data chat",
"scripts": {
"analyze": "cross-env ANALYZE=1 umi build",
"analyze": "cross-env ANALYZE=1 max build",
"build": "npm run build:os",
"build:os": "cross-env REACT_APP_ENV=prod APP_TARGET=opensource umi build",
"build:os-local": "cross-env REACT_APP_ENV=prod APP_TARGET=opensource RUN_TYPE=local umi build",
"build:inner": "cross-env REACT_APP_ENV=prod APP_TARGET=inner umi build",
"build:test": "cross-env REACT_APP_ENV=test umi build",
"build:os": "cross-env REACT_APP_ENV=prod APP_TARGET=opensource max build",
"build:os-local": "cross-env REACT_APP_ENV=prod APP_TARGET=opensource RUN_TYPE=local max build",
"build:inner": "cross-env REACT_APP_ENV=prod APP_TARGET=inner max build",
"build:test": "cross-env REACT_APP_ENV=test max build",
"deploy": "npm run site && npm run gh-pages",
"dev": "npm run start:osdev",
"dev:os": "npm run start:osdev",
"dev:inner": "npm run start:dev",
"no:dev:os": "NODE_OPTIONS=--openssl-legacy-provider npm run start:osdev",
"no:dev:inner": "NODE_OPTIONS=--openssl-legacy-provider npm run start:dev",
"no:build:inner": "cross-env NODE_OPTIONS=--openssl-legacy-provider REACT_APP_ENV=prod APP_TARGET=inner umi build",
"no:build:inner": "cross-env NODE_OPTIONS=--openssl-legacy-provider REACT_APP_ENV=prod APP_TARGET=inner max build",
"gh-pages": "gh-pages -d dist",
"i18n-remove": "pro i18n-remove --locale=zh-CN --write",
"postinstall": "umi g tmp",
"lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier",
"postinstall": "max setup",
"lint": "max g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier",
"lint-staged": "lint-staged",
"lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
"lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
@@ -29,17 +29,17 @@
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
"precommit": "lint-staged",
"prettier": "prettier -c --write \"src/**/*\"",
"start": "NODE_OPTIONS=--openssl-legacy-provider npm run start:osdev",
"start:dev": "cross-env REACT_APP_ENV=dev MOCK=none APP_TARGET=inner umi dev",
"start:osdev": "cross-env REACT_APP_ENV=dev PORT=9000 MOCK=none APP_TARGET=opensource umi dev",
"start:no-mock": "cross-env MOCK=none umi dev",
"start:no-ui": "cross-env UMI_UI=none umi dev",
"start:pre": "cross-env REACT_APP_ENV=pre umi dev",
"start:test": "cross-env REACT_APP_ENV=test MOCK=none umi dev",
"start": "npm run start:osdev",
"start:dev": "cross-env PORT=8002 REACT_APP_ENV=dev MOCK=none APP_TARGET=inner max dev",
"start:osdev": "cross-env REACT_APP_ENV=dev PORT=9000 MOCK=none APP_TARGET=opensource max dev",
"start:no-mock": "cross-env MOCK=none max dev",
"start:no-ui": "cross-env UMI_UI=none max dev",
"start:pre": "cross-env REACT_APP_ENV=pre max dev",
"start:test": "cross-env REACT_APP_ENV=test MOCK=none max dev",
"pretest": "node ./tests/beforeTest",
"test": "umi test",
"test": "max test",
"test:all": "node ./tests/run-tests.js",
"test:component": "umi test ./src/components",
"test:component": "max test ./src/components",
"tsc": "tsc --noEmit"
},
"lint-staged": {
@@ -67,7 +67,7 @@
"@types/numeral": "^2.0.2",
"@types/react-draft-wysiwyg": "^1.13.2",
"@types/react-syntax-highlighter": "^13.5.0",
"@umijs/route-utils": "^1.0.33",
"@umijs/route-utils": "2.2.2",
"ace-builds": "^1.4.12",
"ahooks": "^3.7.7",
"antd": "5.11.2",
@@ -87,6 +87,7 @@
"omit.js": "^2.0.2",
"path-to-regexp": "^2.4.0",
"qs": "^6.9.0",
"query-string": "^9.0.0",
"react": "^17.0.0",
"react-ace": "^9.4.1",
"react-dev-inspector": "^1.8.4",
@@ -97,10 +98,9 @@
"react-split-pane": "^2.0.3",
"react-syntax-highlighter": "^15.4.3",
"sql-formatter": "^2.3.3",
"supersonic-chat-sdk": "^1.0.10",
"supersonic-insights-flow-components": "^1.4.6",
"umi": "3.5",
"umi-request": "^1.4.0"
"supersonic-chat-sdk": "^1.1.6",
"supersonic-insights-flow-components": "^1.4.9",
"umi-request": "1.4.0"
},
"devDependencies": {
"@ant-design/pro-cli": "^2.0.2",
@@ -117,13 +117,9 @@
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-helmet": "^6.1.0",
"@umijs/fabric": "^2.4.0",
"@umijs/plugin-blocks": "^2.0.5",
"@umijs/plugin-esbuild": "^1.0.1",
"@umijs/preset-ant-design-pro": "^1.2.0",
"@umijs/preset-dumi": "^1.1.0-rc.6",
"@umijs/preset-react": "^1.7.4",
"@umijs/yorkie": "^2.0.3",
"@umijs/max": "^4.2.5",
"@umijs/fabric": "^4.0.1",
"@umijs/plugin-model": "^2.6.2",
"carlo": "^0.9.46",
"cross-port-killer": "^1.1.1",
"detect-installer": "^1.0.1",
@@ -138,7 +134,8 @@
"pro-download": "1.0.1",
"puppeteer-core": "^5.0.0",
"stylelint": "^13.0.0",
"typescript": "^4.0.3"
"typescript": "^4.0.3",
"umi-presets-pro": "2.0.2"
},
"engines": {
"node": ">=16.0.0 <20.0.0"

View File

@@ -0,0 +1,196 @@
/**
* loading 占位
* 解决首次加载时白屏的问题
*/
(function () {
const _root = document.querySelector('#root');
if (_root && _root.innerHTML === '') {
_root.innerHTML = `
<style>
html,
body,
#root {
height: 100%;
margin: 0;
padding: 0;
}
#root {
background-repeat: no-repeat;
background-size: 100% auto;
}
.loading-title {
font-size: 1.1rem;
}
.loading-sub-title {
margin-top: 20px;
font-size: 1rem;
color: #888;
}
.page-loading-warp {
display: flex;
align-items: center;
justify-content: center;
padding: 26px;
}
.ant-spin {
position: absolute;
display: none;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
color: rgba(0, 0, 0, 0.65);
color: #1890ff;
font-size: 14px;
font-variant: tabular-nums;
line-height: 1.5;
text-align: center;
list-style: none;
opacity: 0;
-webkit-transition: -webkit-transform 0.3s
cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: -webkit-transform 0.3s
cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
-webkit-font-feature-settings: "tnum";
font-feature-settings: "tnum";
}
.ant-spin-spinning {
position: static;
display: inline-block;
opacity: 1;
}
.ant-spin-dot {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
font-size: 20px;
}
.ant-spin-dot-item {
position: absolute;
display: block;
width: 9px;
height: 9px;
background-color: #1890ff;
border-radius: 100%;
-webkit-transform: scale(0.75);
-ms-transform: scale(0.75);
transform: scale(0.75);
-webkit-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
opacity: 0.3;
-webkit-animation: antspinmove 1s infinite linear alternate;
animation: antSpinMove 1s infinite linear alternate;
}
.ant-spin-dot-item:nth-child(1) {
top: 0;
left: 0;
}
.ant-spin-dot-item:nth-child(2) {
top: 0;
right: 0;
-webkit-animation-delay: 0.4s;
animation-delay: 0.4s;
}
.ant-spin-dot-item:nth-child(3) {
right: 0;
bottom: 0;
-webkit-animation-delay: 0.8s;
animation-delay: 0.8s;
}
.ant-spin-dot-item:nth-child(4) {
bottom: 0;
left: 0;
-webkit-animation-delay: 1.2s;
animation-delay: 1.2s;
}
.ant-spin-dot-spin {
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-animation: antrotate 1.2s infinite linear;
animation: antRotate 1.2s infinite linear;
}
.ant-spin-lg .ant-spin-dot {
width: 32px;
height: 32px;
font-size: 32px;
}
.ant-spin-lg .ant-spin-dot i {
width: 14px;
height: 14px;
}
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.ant-spin-blur {
background: #fff;
opacity: 0.5;
}
}
@-webkit-keyframes antSpinMove {
to {
opacity: 1;
}
}
@keyframes antSpinMove {
to {
opacity: 1;
}
}
@-webkit-keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
</style>
<div style="
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 362px;
">
<div class="page-loading-warp">
<div class="ant-spin ant-spin-lg ant-spin-spinning">
<span class="ant-spin-dot ant-spin-dot-spin">
<i class="ant-spin-dot-item"></i>
<i class="ant-spin-dot-item"></i>
<i class="ant-spin-dot-item"></i>
<i class="ant-spin-dot-item"></i>
</span>
</div>
</div>
</div>
`;
}
})();

View File

@@ -1,6 +1,10 @@
import { ROUTE_AUTH_CODES } from '../config/routes';
export default function access({ authCodes }: { authCodes: string[] }) {
export default function access(params) {
if (!params) {
return {};
}
const { authCodes } = params;
return Object.keys(ROUTE_AUTH_CODES).reduce((result, key) => {
const data = { ...result };
const code = ROUTE_AUTH_CODES[key];

View File

@@ -3,18 +3,16 @@ import S2Icon, { ICON } from '@/components/S2Icon';
import type { Settings as LayoutSettings } from '@ant-design/pro-layout';
import { Space, Spin, ConfigProvider } from 'antd';
import ScaleLoader from 'react-spinners/ScaleLoader';
import type { RunTimeLayoutConfig } from 'umi';
import { history } from 'umi';
import { history, RunTimeLayoutConfig } from '@umijs/max';
import defaultSettings from '../config/defaultSettings';
import settings from '../config/themeSettings';
import { queryCurrentUser } from './services/user';
import { traverseRoutes, isMobile, getToken } from './utils/utils';
import { deleteUrlQuery, isMobile, getToken } from '@/utils/utils';
import { publicPath } from '../config/defaultSettings';
import { Copilot } from 'supersonic-chat-sdk';
import { getSystemConfig } from '@/services/user';
import { configProviderTheme } from '../config/themeSettings';
export { request } from './services/request';
import { ROUTE_AUTH_CODES } from '../config/routes';
import { configProviderTheme } from '../config/themeSettings';
const replaceRoute = '/';
@@ -32,14 +30,6 @@ Spin.setDefaultIndicator(
<ScaleLoader color={settings['primary-color']} height={25} width={2} radius={2} margin={2} />,
);
export const initialStateConfig = {
loading: (
<Spin wrapperClassName="initialLoading">
<div className="loadingPlaceholder" />
</Spin>
),
};
const getAuthCodes = (params: any) => {
const { currentUser } = params;
const codes = [];
@@ -66,7 +56,6 @@ export async function getInitialState(): Promise<{
return undefined;
};
let currentUser: any;
if (!window.location.pathname.includes('login')) {
currentUser = await fetchUserInfo();
@@ -91,33 +80,37 @@ export async function getInitialState(): Promise<{
};
}
export async function patchRoutes({ routes }) {
const config = await getRunningEnv();
if (config && config.env) {
window.RUNNING_ENV = config.env;
const { env } = config;
const target = routes[0].routes;
if (env) {
const envRoutes = traverseRoutes(target, env);
// 清空原本route;
target.splice(0, 99);
// 写入根据环境转换过的的route
target.push(...envRoutes);
}
} else {
const target = routes[0].routes;
// start-standalone模式不存在env在此模式下不显示chatSetting
const envRoutes = target.filter((item: any) => {
return !['chatSetting'].includes(item.name);
});
target.splice(0, 99);
target.push(...envRoutes);
}
}
// export async function patchRoutes({ routes }) {
// const config = await getRunningEnv();
// if (config && config.env) {
// window.RUNNING_ENV = config.env;
// const { env } = config;
// const target = routes[0].routes;
// if (env) {
// const envRoutes = traverseRoutes(target, env);
// // 清空原本route;
// target.splice(0, 99);
// // 写入根据环境转换过的的route
// target.push(...envRoutes);
// }
// } else {
// const target = routes[0].routes;
// // start-standalone模式不存在env在此模式下不显示chatSetting
// const envRoutes = target.filter((item: any) => {
// return !['chatSetting'].includes(item.name);
// });
// target.splice(0, 99);
// target.push(...envRoutes);
// }
// }
export function onRouteChange() {
const title = window.document.title.split('-SuperSonic')[0];
if (!title.includes('SuperSonic')) {
window.document.title = `${title}-SuperSonic`;
} else {
window.document.title = 'SuperSonic';
}
}
export const layout: RunTimeLayoutConfig = (params) => {
@@ -132,21 +125,25 @@ export const layout: RunTimeLayoutConfig = (params) => {
<S2Icon
icon={ICON.iconlogobiaoshi}
size={30}
color="#fff"
color="#1672fa"
style={{ display: 'inline-block', marginTop: 8 }}
/>
<div className="logo">SuperSonic</div>
<div className="logo" style={{ color: '#262626' }}>
SuperSonic
</div>
</Space>
),
contentStyle: { ...(initialState?.contentStyle || {}) },
rightContentRender: () => <RightContent />,
disableContentMargin: true,
menuHeaderRender: undefined,
childrenRender: (dom: any) => {
// menuHeaderRender: undefined,
childrenRender: (dom) => {
return (
<ConfigProvider theme={configProviderTheme}>
<div
style={{ height: location.pathname.includes('chat') ? 'calc(100vh - 56px)' : undefined }}
style={{
height: location.pathname.includes('chat') ? 'calc(100vh - 56px)' : undefined,
}}
>
{dom}
{history.location.pathname !== '/chat' && !isMobile && (

View File

@@ -0,0 +1,3 @@
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.68182 13.6364H1.13636C0.834981 13.6364 0.545943 13.7561 0.332833 13.9692C0.119724 14.1823 0 14.4713 0 14.7727V23.8636C0 24.165 0.119724 24.4541 0.332833 24.6672C0.545943 24.8803 0.834981 25 1.13636 25H5.68182C5.9832 25 6.27224 24.8803 6.48535 24.6672C6.69846 24.4541 6.81818 24.165 6.81818 23.8636V14.7727C6.81818 14.4713 6.69846 14.1823 6.48535 13.9692C6.27224 13.7561 5.9832 13.6364 5.68182 13.6364ZM4.54545 22.7273H2.27273V15.9091H4.54545V22.7273ZM23.8636 9.09091H19.3182C19.0168 9.09091 18.7278 9.21063 18.5147 9.42374C18.3015 9.63685 18.1818 9.92589 18.1818 10.2273V23.8636C18.1818 24.165 18.3015 24.4541 18.5147 24.6672C18.7278 24.8803 19.0168 25 19.3182 25H23.8636C24.165 25 24.4541 24.8803 24.6672 24.6672C24.8803 24.4541 25 24.165 25 23.8636V10.2273C25 9.92589 24.8803 9.63685 24.6672 9.42374C24.4541 9.21063 24.165 9.09091 23.8636 9.09091ZM22.7273 22.7273H20.4545V11.3636H22.7273V22.7273ZM14.7727 0H10.2273C9.92589 0 9.63685 0.119724 9.42374 0.332833C9.21063 0.545943 9.09091 0.834981 9.09091 1.13636V23.8636C9.09091 24.165 9.21063 24.4541 9.42374 24.6672C9.63685 24.8803 9.92589 25 10.2273 25H14.7727C15.0741 25 15.3631 24.8803 15.5763 24.6672C15.7894 24.4541 15.9091 24.165 15.9091 23.8636V1.13636C15.9091 0.834981 15.7894 0.545943 15.5763 0.332833C15.3631 0.119724 15.0741 0 14.7727 0ZM13.6364 22.7273H11.3636V2.27273H13.6364V22.7273Z" fill="#FF694A"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,110 +0,0 @@
/* stylelint-disable */
.bezierEasingMixin() {
@functions: ~`(function() {
var NEWTON_ITERATIONS = 4;
var NEWTON_MIN_SLOPE = 0.001;
var SUBDIVISION_PRECISION = 0.0000001;
var SUBDIVISION_MAX_ITERATIONS = 10;
var kSplineTableSize = 11;
var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
var float32ArraySupported = typeof Float32Array === 'function';
function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
function C (aA1) { return 3.0 * aA1; }
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; }
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); }
function binarySubdivide (aX, aA, aB, mX1, mX2) {
var currentX, currentT, i = 0;
do {
currentT = aA + (aB - aA) / 2.0;
currentX = calcBezier(currentT, mX1, mX2) - aX;
if (currentX > 0.0) {
aB = currentT;
} else {
aA = currentT;
}
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
return currentT;
}
function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) {
for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
var currentSlope = getSlope(aGuessT, mX1, mX2);
if (currentSlope === 0.0) {
return aGuessT;
}
var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
aGuessT -= currentX / currentSlope;
}
return aGuessT;
}
var BezierEasing = function (mX1, mY1, mX2, mY2) {
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
throw new Error('bezier x values must be in [0, 1] range');
}
// Precompute samples table
var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
if (mX1 !== mY1 || mX2 !== mY2) {
for (var i = 0; i < kSplineTableSize; ++i) {
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
}
}
function getTForX (aX) {
var intervalStart = 0.0;
var currentSample = 1;
var lastSample = kSplineTableSize - 1;
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
intervalStart += kSampleStepSize;
}
--currentSample;
// Interpolate to provide an initial guess for t
var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
var guessForT = intervalStart + dist * kSampleStepSize;
var initialSlope = getSlope(guessForT, mX1, mX2);
if (initialSlope >= NEWTON_MIN_SLOPE) {
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
} else if (initialSlope === 0.0) {
return guessForT;
} else {
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
}
}
return function BezierEasing (x) {
if (mX1 === mY1 && mX2 === mY2) {
return x; // linear
}
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
if (x === 0) {
return 0;
}
if (x === 1) {
return 1;
}
return calcBezier(getTForX(x), mY1, mY2);
};
};
this.colorEasing = BezierEasing(0.26, 0.09, 0.37, 0.18);
// less 3 requires a return
return '';
})()`;
}
// It is hacky way to make this function will be compiled preferentially by less
// resolve error: `ReferenceError: colorPalette is not defined`
// https://github.com/ant-design/ant-motion/issues/44
.bezierEasingMixin();

View File

@@ -1,85 +0,0 @@
/* stylelint-disable no-duplicate-selectors */
@import "bezierEasing";
@import "tinyColor";
// We create a very complex algorithm which take the place of original tint/shade color system
// to make sure no one can understand it 👻
// and create an entire color palette magicly by inputing just a single primary color.
// We are using bezier-curve easing function and some color manipulations like tint/shade/darken/spin
.colorPaletteMixin() {
@functions: ~`(function() {
var hueStep = 2;
var saturationStep = 0.16;
var saturationStep2 = 0.05;
var brightnessStep1 = 0.05;
var brightnessStep2 = 0.15;
var lightColorCount = 5;
var darkColorCount = 4;
var getHue = function(hsv, i, isLight) {
var hue;
if (hsv.h >= 60 && hsv.h <= 240) {
hue = isLight ? hsv.h - hueStep * i : hsv.h + hueStep * i;
} else {
hue = isLight ? hsv.h + hueStep * i : hsv.h - hueStep * i;
}
if (hue < 0) {
hue += 360;
} else if (hue >= 360) {
hue -= 360;
}
return Math.round(hue);
};
var getSaturation = function(hsv, i, isLight) {
// grey color don't change saturation
if (hsv.h === 0 && hsv.s === 0) {
return hsv.s;
}
var saturation;
if (isLight) {
saturation = hsv.s - saturationStep * i;
} else if (i === darkColorCount) {
saturation = hsv.s + saturationStep;
} else {
saturation = hsv.s + saturationStep2 * i;
}
if (saturation > 1) {
saturation = 1;
}
if (isLight && i === lightColorCount && saturation > 0.1) {
saturation = 0.1;
}
if (saturation < 0.06) {
saturation = 0.06;
}
return Number(saturation.toFixed(2));
};
var getValue = function(hsv, i, isLight) {
var value;
if (isLight) {
value = hsv.v + brightnessStep1 * i;
}else{
value = hsv.v - brightnessStep2 * i
}
if (value > 1) {
value = 1;
}
return Number(value.toFixed(2))
};
this.colorPalette = function(color, index) {
var isLight = index <= 6;
var hsv = tinycolor(color).toHsv();
var i = isLight ? lightColorCount + 1 - index : index - lightColorCount - 1;
return tinycolor({
h: getHue(hsv, i, isLight),
s: getSaturation(hsv, i, isLight),
v: getValue(hsv, i, isLight),
}).toHexString();
};
})()`;
}
// It is hacky way to make this function will be compiled preferentially by less
// resolve error: `ReferenceError: colorPalette is not defined`
// https://github.com/ant-design/ant-motion/issues/44
.colorPaletteMixin();

View File

@@ -1,162 +0,0 @@
@import 'colorPalette';
// color palettes
@blue-base: #1890ff;
@blue-1: color(~`colorPalette('@{blue-6}', 1) `);
@blue-2: color(~`colorPalette('@{blue-6}', 2) `);
@blue-3: color(~`colorPalette('@{blue-6}', 3) `);
@blue-4: color(~`colorPalette('@{blue-6}', 4) `);
@blue-5: color(~`colorPalette('@{blue-6}', 5) `);
@blue-6: @blue-base;
@blue-7: color(~`colorPalette('@{blue-6}', 7) `);
@blue-8: color(~`colorPalette('@{blue-6}', 8) `);
@blue-9: color(~`colorPalette('@{blue-6}', 9) `);
@blue-10: color(~`colorPalette('@{blue-6}', 10) `);
@purple-base: #722ed1;
@purple-1: color(~`colorPalette('@{purple-6}', 1) `);
@purple-2: color(~`colorPalette('@{purple-6}', 2) `);
@purple-3: color(~`colorPalette('@{purple-6}', 3) `);
@purple-4: color(~`colorPalette('@{purple-6}', 4) `);
@purple-5: color(~`colorPalette('@{purple-6}', 5) `);
@purple-6: @purple-base;
@purple-7: color(~`colorPalette('@{purple-6}', 7) `);
@purple-8: color(~`colorPalette('@{purple-6}', 8) `);
@purple-9: color(~`colorPalette('@{purple-6}', 9) `);
@purple-10: color(~`colorPalette('@{purple-6}', 10) `);
@cyan-base: #13c2c2;
@cyan-1: color(~`colorPalette('@{cyan-6}', 1) `);
@cyan-2: color(~`colorPalette('@{cyan-6}', 2) `);
@cyan-3: color(~`colorPalette('@{cyan-6}', 3) `);
@cyan-4: color(~`colorPalette('@{cyan-6}', 4) `);
@cyan-5: color(~`colorPalette('@{cyan-6}', 5) `);
@cyan-6: @cyan-base;
@cyan-7: color(~`colorPalette('@{cyan-6}', 7) `);
@cyan-8: color(~`colorPalette('@{cyan-6}', 8) `);
@cyan-9: color(~`colorPalette('@{cyan-6}', 9) `);
@cyan-10: color(~`colorPalette('@{cyan-6}', 10) `);
@green-base: #52c41a;
@green-1: color(~`colorPalette('@{green-6}', 1) `);
@green-2: color(~`colorPalette('@{green-6}', 2) `);
@green-3: color(~`colorPalette('@{green-6}', 3) `);
@green-4: color(~`colorPalette('@{green-6}', 4) `);
@green-5: color(~`colorPalette('@{green-6}', 5) `);
@green-6: @green-base;
@green-7: color(~`colorPalette('@{green-6}', 7) `);
@green-8: color(~`colorPalette('@{green-6}', 8) `);
@green-9: color(~`colorPalette('@{green-6}', 9) `);
@green-10: color(~`colorPalette('@{green-6}', 10) `);
@magenta-base: #eb2f96;
@magenta-1: color(~`colorPalette('@{magenta-6}', 1) `);
@magenta-2: color(~`colorPalette('@{magenta-6}', 2) `);
@magenta-3: color(~`colorPalette('@{magenta-6}', 3) `);
@magenta-4: color(~`colorPalette('@{magenta-6}', 4) `);
@magenta-5: color(~`colorPalette('@{magenta-6}', 5) `);
@magenta-6: @magenta-base;
@magenta-7: color(~`colorPalette('@{magenta-6}', 7) `);
@magenta-8: color(~`colorPalette('@{magenta-6}', 8) `);
@magenta-9: color(~`colorPalette('@{magenta-6}', 9) `);
@magenta-10: color(~`colorPalette('@{magenta-6}', 10) `);
// alias of magenta
@pink-base: #eb2f96;
@pink-1: color(~`colorPalette('@{pink-6}', 1) `);
@pink-2: color(~`colorPalette('@{pink-6}', 2) `);
@pink-3: color(~`colorPalette('@{pink-6}', 3) `);
@pink-4: color(~`colorPalette('@{pink-6}', 4) `);
@pink-5: color(~`colorPalette('@{pink-6}', 5) `);
@pink-6: @pink-base;
@pink-7: color(~`colorPalette('@{pink-6}', 7) `);
@pink-8: color(~`colorPalette('@{pink-6}', 8) `);
@pink-9: color(~`colorPalette('@{pink-6}', 9) `);
@pink-10: color(~`colorPalette('@{pink-6}', 10) `);
@red-base: #f5222d;
@red-1: color(~`colorPalette('@{red-6}', 1) `);
@red-2: color(~`colorPalette('@{red-6}', 2) `);
@red-3: color(~`colorPalette('@{red-6}', 3) `);
@red-4: color(~`colorPalette('@{red-6}', 4) `);
@red-5: color(~`colorPalette('@{red-6}', 5) `);
@red-6: @red-base;
@red-7: color(~`colorPalette('@{red-6}', 7) `);
@red-8: color(~`colorPalette('@{red-6}', 8) `);
@red-9: color(~`colorPalette('@{red-6}', 9) `);
@red-10: color(~`colorPalette('@{red-6}', 10) `);
@orange-base: #fa8c16;
@orange-1: color(~`colorPalette('@{orange-6}', 1) `);
@orange-2: color(~`colorPalette('@{orange-6}', 2) `);
@orange-3: color(~`colorPalette('@{orange-6}', 3) `);
@orange-4: color(~`colorPalette('@{orange-6}', 4) `);
@orange-5: color(~`colorPalette('@{orange-6}', 5) `);
@orange-6: @orange-base;
@orange-7: color(~`colorPalette('@{orange-6}', 7) `);
@orange-8: color(~`colorPalette('@{orange-6}', 8) `);
@orange-9: color(~`colorPalette('@{orange-6}', 9) `);
@orange-10: color(~`colorPalette('@{orange-6}', 10) `);
@yellow-base: #fadb14;
@yellow-1: color(~`colorPalette('@{yellow-6}', 1) `);
@yellow-2: color(~`colorPalette('@{yellow-6}', 2) `);
@yellow-3: color(~`colorPalette('@{yellow-6}', 3) `);
@yellow-4: color(~`colorPalette('@{yellow-6}', 4) `);
@yellow-5: color(~`colorPalette('@{yellow-6}', 5) `);
@yellow-6: @yellow-base;
@yellow-7: color(~`colorPalette('@{yellow-6}', 7) `);
@yellow-8: color(~`colorPalette('@{yellow-6}', 8) `);
@yellow-9: color(~`colorPalette('@{yellow-6}', 9) `);
@yellow-10: color(~`colorPalette('@{yellow-6}', 10) `);
@volcano-base: #fa541c;
@volcano-1: color(~`colorPalette('@{volcano-6}', 1) `);
@volcano-2: color(~`colorPalette('@{volcano-6}', 2) `);
@volcano-3: color(~`colorPalette('@{volcano-6}', 3) `);
@volcano-4: color(~`colorPalette('@{volcano-6}', 4) `);
@volcano-5: color(~`colorPalette('@{volcano-6}', 5) `);
@volcano-6: @volcano-base;
@volcano-7: color(~`colorPalette('@{volcano-6}', 7) `);
@volcano-8: color(~`colorPalette('@{volcano-6}', 8) `);
@volcano-9: color(~`colorPalette('@{volcano-6}', 9) `);
@volcano-10: color(~`colorPalette('@{volcano-6}', 10) `);
@geekblue-base: #2f54eb;
@geekblue-1: color(~`colorPalette('@{geekblue-6}', 1) `);
@geekblue-2: color(~`colorPalette('@{geekblue-6}', 2) `);
@geekblue-3: color(~`colorPalette('@{geekblue-6}', 3) `);
@geekblue-4: color(~`colorPalette('@{geekblue-6}', 4) `);
@geekblue-5: color(~`colorPalette('@{geekblue-6}', 5) `);
@geekblue-6: @geekblue-base;
@geekblue-7: color(~`colorPalette('@{geekblue-6}', 7) `);
@geekblue-8: color(~`colorPalette('@{geekblue-6}', 8) `);
@geekblue-9: color(~`colorPalette('@{geekblue-6}', 9) `);
@geekblue-10: color(~`colorPalette('@{geekblue-6}', 10) `);
@lime-base: #a0d911;
@lime-1: color(~`colorPalette('@{lime-6}', 1) `);
@lime-2: color(~`colorPalette('@{lime-6}', 2) `);
@lime-3: color(~`colorPalette('@{lime-6}', 3) `);
@lime-4: color(~`colorPalette('@{lime-6}', 4) `);
@lime-5: color(~`colorPalette('@{lime-6}', 5) `);
@lime-6: @lime-base;
@lime-7: color(~`colorPalette('@{lime-6}', 7) `);
@lime-8: color(~`colorPalette('@{lime-6}', 8) `);
@lime-9: color(~`colorPalette('@{lime-6}', 9) `);
@lime-10: color(~`colorPalette('@{lime-6}', 10) `);
@gold-base: #faad14;
@gold-1: color(~`colorPalette('@{gold-6}', 1) `);
@gold-2: color(~`colorPalette('@{gold-6}', 2) `);
@gold-3: color(~`colorPalette('@{gold-6}', 3) `);
@gold-4: color(~`colorPalette('@{gold-6}', 4) `);
@gold-5: color(~`colorPalette('@{gold-6}', 5) `);
@gold-6: @gold-base;
@gold-7: color(~`colorPalette('@{gold-6}', 7) `);
@gold-8: color(~`colorPalette('@{gold-6}', 8) `);
@gold-9: color(~`colorPalette('@{gold-6}', 9) `);
@gold-10: color(~`colorPalette('@{gold-6}', 10) `);
@preset-colors: pink, magenta, red, volcano, orange, yellow, gold, cyan, lime, green, blue, geekblue,
purple;

View File

@@ -1,4 +0,0 @@
@root-entry-name: default;
@import './themes/compact.less';
@import './core/index';

View File

@@ -1,10 +0,0 @@
// Config global less under antd
[class^=~'@{ant-prefix}-'],
[class*=~' @{ant-prefix}-'] {
// remove the clear button of a text input control in IE10+
&::-ms-clear,
input::-ms-clear,
input::-ms-reveal {
display: none;
}
}

View File

@@ -1,491 +0,0 @@
/* stylelint-disable property-no-vendor-prefix, at-rule-no-vendor-prefix */
// Reboot
//
// Normalization of HTML elements, manually forked from Normalize.css to remove
// styles targeting irrelevant browsers while applying new styles.
//
// Normalize is licensed MIT. https://github.com/necolas/normalize.css
// HTML & Body reset
@{html-selector},
body {
.square(100%);
}
// remove the clear button of a text input control in IE10+
input::-ms-clear,
input::-ms-reveal {
display: none;
}
// Document
//
// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.
// 2. Change the default font family in all browsers.
// 3. Correct the line height in all browsers.
// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.
// 5. Setting @viewport causes scrollbars to overlap content in IE11 and Edge, so
// we force a non-overlapping, non-auto-hiding scrollbar to counteract.
// 6. Change the default tap highlight to be completely transparent in iOS.
*,
*::before,
*::after {
box-sizing: border-box; // 1
}
@{html-selector} {
font-family: sans-serif; // 2
line-height: 1.15; // 3
-webkit-text-size-adjust: 100%; // 4
-ms-text-size-adjust: 100%; // 4
-ms-overflow-style: scrollbar; // 5
-webkit-tap-highlight-color: fade(@black, 0%); // 6
}
// IE10+ doesn't honor `<meta name="viewport">` in some cases.
@-ms-viewport {
width: device-width;
}
// Body
//
// 1. remove the margin in all browsers.
// 2. As a best practice, apply a default `body-background`.
body {
margin: 0; // 1
color: @text-color;
font-size: @font-size-base;
font-family: @font-family;
font-variant: @font-variant-base;
line-height: @line-height-base;
background-color: @body-background; // 2
font-feature-settings: @font-feature-settings-base;
}
// Suppress the focus outline on elements that cannot be accessed via keyboard.
// This prevents an unwanted focus outline from appearing around elements that
// might still respond to pointer events.
//
// Credit: https://github.com/suitcss/base
[tabindex='-1']:focus {
outline: none !important;
}
// Content grouping
//
// 1. Add the correct box sizing in Firefox.
// 2. Show the overflow in Edge and IE.
hr {
box-sizing: content-box; // 1
height: 0; // 1
overflow: visible; // 2
}
//
// Typography
//
// remove top margins from headings
//
// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top
// margin for easier control within type scales as it avoids margin collapsing.
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
margin-bottom: 0.5em;
color: @heading-color;
font-weight: 500;
}
// Reset margins on paragraphs
//
// Similarly, the top margin on `<p>`s get reset. However, we also reset the
// bottom margin to use `em` units instead of `em`.
p {
margin-top: 0;
margin-bottom: 1em;
}
// Abbreviations
//
// 1. remove the bottom border in Firefox 39-.
// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
// 3. Add explicit cursor to indicate changed behavior.
// 4. Duplicate behavior to the data-* attribute for our tooltip plugin
abbr[title],
abbr[data-original-title] {
// 4
text-decoration: underline; // 2
text-decoration: underline dotted; // 2
border-bottom: 0; // 1
cursor: help; // 3
}
address {
margin-bottom: 1em;
font-style: normal;
line-height: inherit;
}
input[type='text'],
input[type='password'],
input[type='number'],
textarea {
-webkit-appearance: none;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1em;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 500;
}
dd {
margin-bottom: 0.5em;
margin-left: 0; // Undo browser default
}
blockquote {
margin: 0 0 1em;
}
dfn {
font-style: italic; // Add the correct font style in Android 4.3-
}
b,
strong {
font-weight: bolder; // Add the correct font weight in Chrome, Edge, and Safari
}
small {
font-size: 80%; // Add the correct font size in all browsers
}
//
// Prevent `sub` and `sup` elements from affecting the line height in
// all browsers.
//
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
//
// Links
//
a {
color: @link-color;
text-decoration: @link-decoration;
background-color: transparent; // remove the gray background on active links in IE 10.
outline: none;
cursor: pointer;
transition: color 0.3s;
-webkit-text-decoration-skip: objects; // remove gaps in links underline in iOS 8+ and Safari 8+.
&:hover {
color: @link-hover-color;
}
&:active {
color: @link-active-color;
}
&:active,
&:hover {
text-decoration: @link-hover-decoration;
outline: 0;
}
// https://github.com/ant-design/ant-design/issues/22503
&:focus {
text-decoration: @link-focus-decoration;
outline: @link-focus-outline;
}
&[disabled] {
color: @disabled-color;
cursor: not-allowed;
}
}
//
// Code
//
pre,
code,
kbd,
samp {
font-size: 1em; // Correct the odd `em` font sizing in all browsers.
font-family: @code-family;
}
pre {
// remove browser default top margin
margin-top: 0;
// Reset browser default of `1em` to use `em`s
margin-bottom: 1em;
// Don't allow content to break outside
overflow: auto;
}
//
// Figures
//
figure {
// Apply a consistent margin strategy (matches our type styles).
margin: 0 0 1em;
}
//
// Images and content
//
img {
vertical-align: middle;
border-style: none; // remove the border on images inside links in IE 10-.
}
// Avoid 300ms click delay on touch devices that support the `touch-action` CSS property.
//
// In particular, unlike most other browsers, IE11+Edge on Windows 10 on touch devices and IE Mobile 10-11
// DON'T remove the click delay when `<meta name="viewport" content="width=device-width">` is present.
// However, they DO support emoving the click delay via `touch-action: manipulation`.
// See:
// * https://getbootstrap.com/docs/4.0/content/reboot/#click-delay-optimization-for-touch
// * http://caniuse.com/#feat=css-touch-action
// * https://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay
a,
area,
button,
[role='button'],
input:not([type='range']),
label,
select,
summary,
textarea {
touch-action: manipulation;
}
//
// Tables
//
table {
border-collapse: collapse; // Prevent double borders
}
caption {
padding-top: 0.75em;
padding-bottom: 0.3em;
color: @text-color-secondary;
text-align: left;
caption-side: bottom;
}
//
// Forms
//
input,
button,
select,
optgroup,
textarea {
margin: 0; // remove the margin in Firefox and Safari
color: inherit;
font-size: inherit;
font-family: inherit;
line-height: inherit;
}
button,
input {
overflow: visible; // Show the overflow in Edge
}
button,
select {
text-transform: none; // remove the inheritance of text transform in Firefox
}
// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
// controls in Android 4.
// 2. Correct the inability to style clickable types in iOS and Safari.
button,
@{html-selector} [type="button"], /* 1 */
[type="reset"],
[type="submit"] {
-webkit-appearance: button; // 2
}
// remove inner border and padding from Firefox, but don't restore the outline like Normalize.
button::-moz-focus-inner,
[type='button']::-moz-focus-inner,
[type='reset']::-moz-focus-inner,
[type='submit']::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type='radio'],
input[type='checkbox'] {
box-sizing: border-box; // 1. Add the correct box sizing in IE 10-
padding: 0; // 2. remove the padding in IE 10-
}
input[type='date'],
input[type='time'],
input[type='datetime-local'],
input[type='month'] {
// remove the default appearance of temporal inputs to avoid a Mobile Safari
// bug where setting a custom line-height prevents text from being vertically
// centered within the input.
// See https://bugs.webkit.org/show_bug.cgi?id=139848
// and https://github.com/twbs/bootstrap/issues/11266
-webkit-appearance: listbox;
}
textarea {
overflow: auto; // remove the default vertical scrollbar in IE.
// Textareas should really only resize vertically so they don't break their (horizontal) containers.
resize: vertical;
}
fieldset {
// Browsers set a default `min-width: min-content;` on fieldsets,
// unlike e.g. `<div>`s, which have `min-width: 0;` by default.
// So we reset that to ensure fieldsets behave more like a standard block element.
// See https://github.com/twbs/bootstrap/issues/12359
// and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements
min-width: 0;
margin: 0;
// Reset the default outline behavior of fieldsets so they don't affect page layout.
padding: 0;
border: 0;
}
// 1. Correct the text wrapping in Edge and IE.
// 2. Correct the color inheritance from `fieldset` elements in IE.
legend {
display: block;
width: 100%;
max-width: 100%; // 1
margin-bottom: 0.5em;
padding: 0;
color: inherit; // 2
font-size: 1.5em;
line-height: inherit;
white-space: normal; // 1
}
progress {
vertical-align: baseline; // Add the correct vertical alignment in Chrome, Firefox, and Opera.
}
// Correct the cursor style of incement and decement buttons in Chrome.
[type='number']::-webkit-inner-spin-button,
[type='number']::-webkit-outer-spin-button {
height: auto;
}
[type='search'] {
// This overrides the extra rounded corners on search inputs in iOS so that our
// `.form-control` class can properly style them. Note that this cannot simply
// be added to `.form-control` as it's not specific enough. For details, see
// https://github.com/twbs/bootstrap/issues/11586.
outline-offset: -2px; // 2. Correct the outline style in Safari.
-webkit-appearance: none;
}
//
// remove the inner padding and cancel buttons in Chrome and Safari on macOS.
//
[type='search']::-webkit-search-cancel-button,
[type='search']::-webkit-search-decoration {
-webkit-appearance: none;
}
//
// 1. Correct the inability to style clickable types in iOS and Safari.
// 2. Change font properties to `inherit` in Safari.
//
::-webkit-file-upload-button {
font: inherit; // 2
-webkit-appearance: button; // 1
}
//
// Correct element displays
//
output {
display: inline-block;
}
summary {
display: list-item; // Add the correct display in all browsers
}
template {
display: none; // Add the correct display in IE
}
// Always hide an element with the `hidden` HTML attribute (from PureCSS).
// Needed for proper display in IE 10-.
[hidden] {
display: none !important;
}
mark {
padding: 0.2em;
background-color: @yellow-1;
}
::selection {
color: @text-color-inverse;
background: @text-selection-bg;
}
// Utility classes
.clearfix {
.clearfix();
}

View File

@@ -1,22 +0,0 @@
@import '../themes/index';
@import '../mixins/iconfont';
.@{iconfont-css-prefix} {
.iconfont-mixin();
// https://github.com/ant-design/ant-design/issues/33703
& > & {
line-height: 0;
vertical-align: 0;
}
&[tabindex] {
cursor: pointer;
}
}
.@{iconfont-css-prefix}-spin,
.@{iconfont-css-prefix}-spin::before {
display: inline-block;
animation: loadingCircle 1s infinite linear;
}

View File

@@ -1,5 +0,0 @@
@import '../mixins/index';
@import 'base';
@import 'global';
@import 'iconfont';
@import 'motion';

View File

@@ -1,22 +0,0 @@
// @import '../mixins/motion'; This has moved to theme/xxx inside.
@import 'motion/fade';
@import 'motion/move';
@import 'motion/other';
@import 'motion/slide';
@import 'motion/zoom';
// For common/openAnimation
.ant-motion-collapse-legacy {
overflow: hidden;
&-active {
transition: height @animation-duration-base @ease-in-out,
opacity @animation-duration-base @ease-in-out !important;
}
}
.ant-motion-collapse {
overflow: hidden;
transition: height @animation-duration-base @ease-in-out,
opacity @animation-duration-base @ease-in-out !important;
}

View File

@@ -1,34 +0,0 @@
.fade-motion(@className, @keyframeName) {
@name: ~'@{ant-prefix}-@{className}';
.make-motion(@name, @keyframeName);
.@{name}-enter,
.@{name}-appear {
opacity: 0;
animation-timing-function: linear;
}
.@{name}-leave {
animation-timing-function: linear;
}
}
.fade-motion(fade, antFade);
@keyframes antFadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes antFadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}

View File

@@ -1,129 +0,0 @@
.move-motion(@className, @keyframeName) {
@name: ~'@{ant-prefix}-@{className}';
.make-motion(@name, @keyframeName);
.@{name}-enter,
.@{name}-appear {
opacity: 0;
animation-timing-function: @ease-out-circ;
}
.@{name}-leave {
animation-timing-function: @ease-in-circ;
}
}
.move-motion(move-up, antMoveUp);
.move-motion(move-down, antMoveDown);
.move-motion(move-left, antMoveLeft);
.move-motion(move-right, antMoveRight);
@keyframes antMoveDownIn {
0% {
transform: translateY(100%);
transform-origin: 0 0;
opacity: 0;
}
100% {
transform: translateY(0%);
transform-origin: 0 0;
opacity: 1;
}
}
@keyframes antMoveDownOut {
0% {
transform: translateY(0%);
transform-origin: 0 0;
opacity: 1;
}
100% {
transform: translateY(100%);
transform-origin: 0 0;
opacity: 0;
}
}
@keyframes antMoveLeftIn {
0% {
transform: translateX(-100%);
transform-origin: 0 0;
opacity: 0;
}
100% {
transform: translateX(0%);
transform-origin: 0 0;
opacity: 1;
}
}
@keyframes antMoveLeftOut {
0% {
transform: translateX(0%);
transform-origin: 0 0;
opacity: 1;
}
100% {
transform: translateX(-100%);
transform-origin: 0 0;
opacity: 0;
}
}
@keyframes antMoveRightIn {
0% {
transform: translateX(100%);
transform-origin: 0 0;
opacity: 0;
}
100% {
transform: translateX(0%);
transform-origin: 0 0;
opacity: 1;
}
}
@keyframes antMoveRightOut {
0% {
transform: translateX(0%);
transform-origin: 0 0;
opacity: 1;
}
100% {
transform: translateX(100%);
transform-origin: 0 0;
opacity: 0;
}
}
@keyframes antMoveUpIn {
0% {
transform: translateY(-100%);
transform-origin: 0 0;
opacity: 0;
}
100% {
transform: translateY(0%);
transform-origin: 0 0;
opacity: 1;
}
}
@keyframes antMoveUpOut {
0% {
transform: translateY(0%);
transform-origin: 0 0;
opacity: 1;
}
100% {
transform: translateY(-100%);
transform-origin: 0 0;
opacity: 0;
}
}

View File

@@ -1,51 +0,0 @@
@keyframes loadingCircle {
100% {
transform: rotate(360deg);
}
}
@click-animating-true: ~"[@{ant-prefix}-click-animating='true']";
@click-animating-with-extra-node-true: ~"[@{ant-prefix}-click-animating-without-extra-node='true']";
@{click-animating-true},
@{click-animating-with-extra-node-true} {
position: relative;
}
html {
--antd-wave-shadow-color: @primary-color;
--scroll-bar: 0;
}
@click-animating-with-extra-node-true-after: ~'@{click-animating-with-extra-node-true}::after';
@{click-animating-with-extra-node-true-after},
.@{ant-prefix}-click-animating-node {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: block;
border-radius: inherit;
box-shadow: 0 0 0 0 @primary-color;
box-shadow: 0 0 0 0 var(--antd-wave-shadow-color);
opacity: 0.2;
animation: fadeEffect 2s @ease-out-circ, waveEffect 0.4s @ease-out-circ;
animation-fill-mode: forwards;
content: '';
pointer-events: none;
}
@keyframes waveEffect {
100% {
box-shadow: 0 0 0 @primary-color;
box-shadow: 0 0 0 @wave-animation-width var(--antd-wave-shadow-color);
}
}
@keyframes fadeEffect {
100% {
opacity: 0;
}
}

View File

@@ -1,131 +0,0 @@
.slide-motion(@className, @keyframeName) {
@name: ~'@{ant-prefix}-@{className}';
.make-motion(@name, @keyframeName);
.@{name}-enter,
.@{name}-appear {
transform: scale(0);
transform-origin: 0% 0%;
opacity: 0;
animation-timing-function: @ease-out-quint;
}
.@{name}-leave {
animation-timing-function: @ease-in-quint;
}
}
.slide-motion(slide-up, antSlideUp);
.slide-motion(slide-down, antSlideDown);
.slide-motion(slide-left, antSlideLeft);
.slide-motion(slide-right, antSlideRight);
@keyframes antSlideUpIn {
0% {
transform: scaleY(0.8);
transform-origin: 0% 0%;
opacity: 0;
}
100% {
transform: scaleY(1);
transform-origin: 0% 0%;
opacity: 1;
}
}
@keyframes antSlideUpOut {
0% {
transform: scaleY(1);
transform-origin: 0% 0%;
opacity: 1;
}
100% {
transform: scaleY(0.8);
transform-origin: 0% 0%;
opacity: 0;
}
}
@keyframes antSlideDownIn {
0% {
transform: scaleY(0.8);
transform-origin: 100% 100%;
opacity: 0;
}
100% {
transform: scaleY(1);
transform-origin: 100% 100%;
opacity: 1;
}
}
@keyframes antSlideDownOut {
0% {
transform: scaleY(1);
transform-origin: 100% 100%;
opacity: 1;
}
100% {
transform: scaleY(0.8);
transform-origin: 100% 100%;
opacity: 0;
}
}
@keyframes antSlideLeftIn {
0% {
transform: scaleX(0.8);
transform-origin: 0% 0%;
opacity: 0;
}
100% {
transform: scaleX(1);
transform-origin: 0% 0%;
opacity: 1;
}
}
@keyframes antSlideLeftOut {
0% {
transform: scaleX(1);
transform-origin: 0% 0%;
opacity: 1;
}
100% {
transform: scaleX(0.8);
transform-origin: 0% 0%;
opacity: 0;
}
}
@keyframes antSlideRightIn {
0% {
transform: scaleX(0.8);
transform-origin: 100% 0%;
opacity: 0;
}
100% {
transform: scaleX(1);
transform-origin: 100% 0%;
opacity: 1;
}
}
@keyframes antSlideRightOut {
0% {
transform: scaleX(1);
transform-origin: 100% 0%;
opacity: 1;
}
100% {
transform: scaleX(0.8);
transform-origin: 100% 0%;
opacity: 0;
}
}

View File

@@ -1,179 +0,0 @@
.zoom-motion(@className, @keyframeName, @duration: @animation-duration-base) {
@name: ~'@{ant-prefix}-@{className}';
.make-motion(@name, @keyframeName, @duration);
.@{name}-enter,
.@{name}-appear {
transform: scale(0); // need this by yiminghe
opacity: 0;
animation-timing-function: @ease-out-circ;
&-prepare {
transform: none;
}
}
.@{name}-leave {
animation-timing-function: @ease-in-out-circ;
}
}
// For Modal, Select choosen item
.zoom-motion(zoom, antZoom);
// For Popover, Popconfirm, Dropdown
.zoom-motion(zoom-big, antZoomBig);
// For Tooltip
.zoom-motion(zoom-big-fast, antZoomBig, @animation-duration-fast);
.zoom-motion(zoom-up, antZoomUp);
.zoom-motion(zoom-down, antZoomDown);
.zoom-motion(zoom-left, antZoomLeft);
.zoom-motion(zoom-right, antZoomRight);
@keyframes antZoomIn {
0% {
transform: scale(0.2);
opacity: 0;
}
100% {
transform: scale(1);
opacity: 1;
}
}
@keyframes antZoomOut {
0% {
transform: scale(1);
}
100% {
transform: scale(0.2);
opacity: 0;
}
}
@keyframes antZoomBigIn {
0% {
transform: scale(0.8);
opacity: 0;
}
100% {
transform: scale(1);
opacity: 1;
}
}
@keyframes antZoomBigOut {
0% {
transform: scale(1);
}
100% {
transform: scale(0.8);
opacity: 0;
}
}
@keyframes antZoomUpIn {
0% {
transform: scale(0.8);
transform-origin: 50% 0%;
opacity: 0;
}
100% {
transform: scale(1);
transform-origin: 50% 0%;
}
}
@keyframes antZoomUpOut {
0% {
transform: scale(1);
transform-origin: 50% 0%;
}
100% {
transform: scale(0.8);
transform-origin: 50% 0%;
opacity: 0;
}
}
@keyframes antZoomLeftIn {
0% {
transform: scale(0.8);
transform-origin: 0% 50%;
opacity: 0;
}
100% {
transform: scale(1);
transform-origin: 0% 50%;
}
}
@keyframes antZoomLeftOut {
0% {
transform: scale(1);
transform-origin: 0% 50%;
}
100% {
transform: scale(0.8);
transform-origin: 0% 50%;
opacity: 0;
}
}
@keyframes antZoomRightIn {
0% {
transform: scale(0.8);
transform-origin: 100% 50%;
opacity: 0;
}
100% {
transform: scale(1);
transform-origin: 100% 50%;
}
}
@keyframes antZoomRightOut {
0% {
transform: scale(1);
transform-origin: 100% 50%;
}
100% {
transform: scale(0.8);
transform-origin: 100% 50%;
opacity: 0;
}
}
@keyframes antZoomDownIn {
0% {
transform: scale(0.8);
transform-origin: 50% 100%;
opacity: 0;
}
100% {
transform: scale(1);
transform-origin: 50% 100%;
}
}
@keyframes antZoomDownOut {
0% {
transform: scale(1);
transform-origin: 50% 100%;
}
100% {
transform: scale(0.8);
transform-origin: 50% 100%;
opacity: 0;
}
}

View File

@@ -1 +0,0 @@
import './index.css';

View File

@@ -1,4 +0,0 @@
@root-entry-name: default;
@import './themes/dark.less';
@import './core/index';

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +0,0 @@
// This is same as `index.less` but given `root-entry-name` for `dist/antd.less` usage
@root-entry-name: default;
@import './index';

View File

@@ -1,2 +0,0 @@
@import './themes/index';
@import './core/index';

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
import './index.less';

View File

@@ -1 +0,0 @@
import './index.less';

View File

@@ -1,3 +0,0 @@
@root-entry-name: default;
@import './index-pure.less';

View File

@@ -1,7 +0,0 @@
.box(@position: absolute) {
position: @position;
top: 0;
right: 0;
bottom: 0;
left: 0;
}

View File

@@ -1,16 +0,0 @@
// mixins for clearfix
// ------------------------
.clearfix() {
// https://github.com/ant-design/ant-design/issues/21301#issuecomment-583955229
&::before {
display: table;
content: '';
}
&::after {
// https://github.com/ant-design/ant-design/issues/21864
display: table;
clear: both;
content: '';
}
}

View File

@@ -1,41 +0,0 @@
.compact-item-vertical-border-radius(@prefix-cls) {
&-item:not(&-first-item):not(&-last-item) {
border-radius: 0;
}
&-item&-first-item:not(&-last-item) {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
&-item&-last-item:not(&-first-item) {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
.compact-item-vertical-border(@prefix-cls) {
// border collapse
&-item:not(&-last-item) {
margin-bottom: -@border-width-base;
}
&-item {
&:hover,
&:focus,
&:active {
z-index: 2;
}
&[disabled] {
z-index: 0;
}
}
}
.compact-item-vertical(@prefix-cls) {
&-compact-vertical {
.compact-item-vertical-border(@prefix-cls);
.compact-item-vertical-border-radius(@prefix-cls);
}
}

View File

@@ -1,133 +0,0 @@
.compact-item-border-radius(@prefix-cls, @bordered-item-cls: null) {
& when (@bordered-item-cls = null) {
// border-radius
&-item:not(&-first-item):not(&-last-item).@{prefix-cls} {
border-radius: 0;
}
&-item.@{prefix-cls}&-first-item:not(&-last-item):not(&-item-rtl) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&-item.@{prefix-cls}&-last-item:not(&-first-item):not(&-item-rtl) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
// ----------rtl for first item----------
&-item.@{prefix-cls}&-item-rtl&-first-item:not(&-last-item) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
// ----------rtl for last item----------
&-item.@{prefix-cls}&-item-rtl&-last-item:not(&-first-item) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
& when (not (@bordered-item-cls = null)) {
// border-radius
&-item:not(&-first-item):not(&-last-item).@{prefix-cls} > .@{bordered-item-cls} {
border-radius: 0;
}
&-item&-first-item.@{prefix-cls}:not(&-last-item):not(&-item-rtl) > .@{bordered-item-cls} {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&-item&-last-item.@{prefix-cls}:not(&-first-item):not(&-item-rtl) > .@{bordered-item-cls} {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
// ----------rtl for first item----------
&-item.@{prefix-cls}&-first-item&-item-rtl:not(&-last-item) > .@{bordered-item-cls} {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
// ----------rtl for last item----------
&-item.@{prefix-cls}&-last-item&-item-rtl:not(&-first-item) > .@{bordered-item-cls} {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
}
.compact-item-border(@prefix-cls, @bordered-item-cls: null, @special-open-cls) {
& when (@bordered-item-cls = null) {
// border collapse
&-item:not(&-last-item):not(&-item-rtl) {
margin-right: -@border-width-base;
}
// rtl border collapse
&-item:not(&-last-item)&-item-rtl {
margin-left: -@border-width-base;
}
&-item {
&:hover,
&:focus,
&:active {
z-index: 2;
}
// Select has an extra focus className
& when (not (@special-item-cls = null)) {
&.@{special-item-cls} {
z-index: 2;
}
}
&[disabled] {
z-index: 0;
}
}
}
& when (not (@bordered-item-cls = null)) {
// border collapse
&-item:not(&-last-item) {
margin-right: -@border-width-base;
&.@{prefix-cls}-compact-item-rtl {
margin-right: 0;
margin-left: -@border-width-base;
}
}
&-item {
&:hover,
&:focus,
&:active {
> * {
z-index: 2;
}
}
// Select has an special focus-item
& when (not (@special-item-cls = null)) {
&.@{special-item-cls} > * {
z-index: 2;
}
}
&[disabled] > * {
z-index: 0;
}
}
}
}
.compact-item(@prefix-cls, @bordered-item-cls: null, @special-item-cls: null) {
&-compact {
.compact-item-border(@prefix-cls, @bordered-item-cls, @special-item-cls);
.compact-item-border-radius(@prefix-cls, @bordered-item-cls);
}
}

View File

@@ -1,13 +0,0 @@
// Compatibility for browsers.
// Placeholder text
.placeholder(@color: @input-placeholder-color) {
&::placeholder {
color: @color;
user-select: none; // https://github.com/ant-design/ant-design/pull/32639
}
&:placeholder-shown {
text-overflow: ellipsis;
}
}

View File

@@ -1,181 +0,0 @@
// customize dark components background in popover containers(like Modal, Drawer, Card, Popover, Popconfirm, Notification, ...)
// for dark theme
.popover-customize-bg(@containerClass, @background: @popover-background, @prefix: @ant-prefix)
when
(@theme = dark) {
@picker-prefix-cls: ~'@{prefix}-picker';
@slider-prefix-cls: ~'@{prefix}-slider';
@anchor-prefix-cls: ~'@{prefix}-anchor';
@collapse-prefix-cls: ~'@{prefix}-collapse';
@tab-prefix-cls: ~'@{prefix}-tabs';
@timeline-prefix-cls: ~'@{prefix}-timeline';
@tree-prefix-cls: ~'@{prefix}-tree';
@card-prefix-cls: ~'@{prefix}-card';
@badge-prefix-cls: ~'@{prefix}-badge';
@transfer-prefix-cls: ~'@{prefix}-transfer';
@calendar-prefix-cls: ~'@{prefix}-picker-calendar';
@calendar-picker-prefix-cls: ~'@{prefix}-picker';
@table-prefix-cls: ~'@{prefix}-table';
@popover-border: @border-width-base @border-style-base @popover-customize-border-color;
.@{containerClass} {
.@{picker-prefix-cls}-clear,
.@{slider-prefix-cls}-handle,
.@{anchor-prefix-cls}-wrapper,
.@{collapse-prefix-cls}-content,
.@{timeline-prefix-cls}-item-head,
.@{card-prefix-cls} {
background-color: @background;
}
.@{transfer-prefix-cls} {
&-list {
&-header {
background: @background;
border-bottom: @popover-border;
}
&-content-item:not(.@{transfer-prefix-cls}-list-content-item-disabled):hover {
background-color: @item-hover-bg;
}
}
}
tr.@{table-prefix-cls}-expanded-row {
&,
&:hover {
> td {
background: #272727;
}
}
}
.@{table-prefix-cls}.@{table-prefix-cls}-small {
thead {
> tr {
> th {
background-color: @background;
border-bottom: @popover-border;
}
}
}
}
.@{table-prefix-cls} {
background-color: @background;
.@{table-prefix-cls}-row-expand-icon {
border: @popover-border;
}
tfoot {
> tr {
> th,
> td {
border-bottom: @popover-border;
}
}
}
thead {
> tr {
> th {
background-color: #272727;
border-bottom: @popover-border;
}
}
}
tbody {
> tr {
> td {
border-bottom: @popover-border;
&.@{table-prefix-cls}-cell-fix-left,
&.@{table-prefix-cls}-cell-fix-right {
background-color: @background;
}
}
&.@{table-prefix-cls}-row:hover {
> td {
background: @table-header-sort-active-bg;
}
}
}
}
&.@{table-prefix-cls}-bordered {
.@{table-prefix-cls}-title {
border: @popover-border;
}
// ============================= Cell =============================
thead > tr > th,
tbody > tr > td,
tfoot > tr > th,
tfoot > tr > td {
border-right: @popover-border;
}
// Fixed right should provides additional border
.@{table-prefix-cls}-cell-fix-right-first::after {
border-right: @popover-border;
}
// ============================ Header ============================
table > {
thead {
> tr:not(:last-child) > th {
border-bottom: @border-width-base @border-style-base @border-color-split;
}
}
}
// =========================== Content ============================
.@{table-prefix-cls}-container {
border: @popover-border;
}
// ========================== Expandable ==========================
.@{table-prefix-cls}-expanded-row-fixed {
&::after {
border-right: @popover-border;
}
}
.@{table-prefix-cls}-footer {
border: @popover-border;
}
}
.@{table-prefix-cls}-filter-trigger-container-open {
background-color: #525252;
}
}
.@{calendar-prefix-cls}-full {
background-color: @background;
.@{calendar-picker-prefix-cls}-panel {
background-color: @background;
.@{calendar-prefix-cls}-date {
border-top: 2px solid @popover-customize-border-color;
}
}
}
.@{tab-prefix-cls} {
&.@{tab-prefix-cls}-card .@{tab-prefix-cls}-card-bar .@{tab-prefix-cls}-tab-active {
background-color: @background;
border-bottom: @border-width-base solid @background;
}
}
.@{badge-prefix-cls} {
&-count {
box-shadow: 0 0 0 1px @background;
}
}
.@{tree-prefix-cls} {
&-show-line {
.@{tree-prefix-cls}-switcher {
background: @background;
}
}
}
}
}

View File

@@ -1,29 +0,0 @@
.iconfont-mixin() {
display: inline-flex;
align-items: center;
color: @icon-color;
font-style: normal;
line-height: 0;
text-align: center;
text-transform: none;
vertical-align: -0.125em; // for SVG icon, see https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4
text-rendering: optimizelegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
> * {
line-height: 1;
}
svg {
display: inline-block;
}
&::before {
display: none; // dont display old icon.
}
& &-icon {
display: block;
}
}

View File

@@ -1,16 +0,0 @@
// Mixins
// --------------------------------------------------
@import 'size';
@import 'compatibility';
@import 'clearfix';
@import 'iconfont';
@import 'typography';
@import 'customize';
@import 'box';
@import 'modal-mask';
@import 'motion';
@import 'reset';
@import 'operation-unit';
@import 'rounded-arrow';
@import 'compact-item';
@import 'compact-item-vertical';

View File

@@ -1,30 +0,0 @@
@import 'box';
.modal-mask() {
pointer-events: none;
&.@{ant-prefix}-zoom-enter,
&.@{ant-prefix}-zoom-appear {
transform: none; // reset scale avoid mousePosition bug
opacity: 0;
animation-duration: @animation-duration-slow;
user-select: none; // https://github.com/ant-design/ant-design/issues/11777
}
&-mask {
.box(fixed);
z-index: @zindex-modal-mask;
height: 100%;
background-color: @modal-mask-bg;
&-hidden {
display: none;
}
}
&-wrap {
.box(fixed);
overflow: auto;
outline: 0;
}
}

View File

@@ -1,33 +0,0 @@
.motion-common(@duration: @animation-duration-base) {
animation-duration: @duration;
animation-fill-mode: both;
}
.motion-common-leave(@duration: @animation-duration-base) {
animation-duration: @duration;
animation-fill-mode: both;
}
.make-motion(@className, @keyframeName, @duration: @animation-duration-base) {
.@{className}-enter,
.@{className}-appear {
.motion-common(@duration);
animation-play-state: paused;
}
.@{className}-leave {
.motion-common-leave(@duration);
animation-play-state: paused;
}
.@{className}-enter.@{className}-enter-active,
.@{className}-appear.@{className}-appear-active {
animation-name: ~'@{keyframeName}In';
animation-play-state: running;
}
.@{className}-leave.@{className}-leave-active {
animation-name: ~'@{keyframeName}Out';
animation-play-state: running;
pointer-events: none;
}
}

View File

@@ -1,15 +0,0 @@
.operation-unit() {
color: @link-color;
outline: none;
cursor: pointer;
transition: color 0.3s;
&:focus-visible,
&:hover {
color: @link-hover-color;
}
&:active {
color: @link-active-color;
}
}

View File

@@ -1,11 +0,0 @@
.reset-component() {
box-sizing: border-box;
margin: 0;
padding: 0;
color: @text-color;
font-size: @font-size-base;
font-variant: @font-variant-base;
line-height: @line-height-base;
list-style: none;
font-feature-settings: @font-feature-settings-base;
}

View File

@@ -1,44 +0,0 @@
.roundedArrow(@width, @outer-radius, @bg-color: var(--antd-arrow-background-color)) {
@corner-height: unit(((@outer-radius) * (1 - 1 / sqrt(2))));
@width-without-unit: unit(@width);
@outer-radius-without-unit: unit(@outer-radius);
@inner-radius-without-unit: unit(@arrow-border-radius);
@a-x: @width-without-unit - @corner-height;
@a-y: 2 * @width-without-unit + @corner-height;
@b-x: @a-x + @outer-radius-without-unit * (1 / sqrt(2));
@b-y: 2 * @width-without-unit;
@c-x: 2 * @width-without-unit - @inner-radius-without-unit;
@c-y: 2 * @width-without-unit;
@d-x: 2 * @width-without-unit;
@d-y: 2 * @width-without-unit - @inner-radius-without-unit;
@e-x: 2 * @width-without-unit;
@e-y: @f-y + @outer-radius-without-unit * (1 / sqrt(2));
@f-x: 2 * @width-without-unit + @corner-height;
@f-y: @width-without-unit - @corner-height;
@g-x: @f-x - 1;
@g-y: @f-y;
@h-x: @a-x;
@h-y: @a-y - 1;
border-radius: 0 0 @arrow-border-radius;
pointer-events: none;
&::before {
position: absolute;
top: -@width;
left: -@width;
width: @width * 3;
height: @width * 3;
background: @bg-color;
// Hack firefox: https://github.com/ant-design/ant-design/pull/33710#issuecomment-1015287825
background-repeat: no-repeat;
background-position: ceil(-@width + 1px) ceil(-@width + 1px);
content: '';
clip-path: inset(33% 33%); // For browsers that do not support path()
clip-path: path(
'M @{a-x} @{a-y} A @{outer-radius-without-unit} @{outer-radius-without-unit} 0 0 1 @{b-x} @{b-y} L @{c-x} @{c-y} A @{inner-radius-without-unit} @{inner-radius-without-unit} 0 0 0 @{d-x} @{d-y} L @{e-x} @{e-y} A @{outer-radius-without-unit} @{outer-radius-without-unit} 0 0 1 @{f-x} @{f-y} L @{g-x} @{g-y} L @{h-x} @{h-y} Z'
);
}
}

View File

@@ -1,10 +0,0 @@
// Sizing shortcuts
.size(@width; @height) {
width: @width;
height: @height;
}
.square(@size) {
.size(@size; @size);
}

View File

@@ -1,58 +0,0 @@
// =============== Common ===============
.typography-paragraph() {
margin-bottom: 1em;
}
.typography-title(@fontSize; @fontWeight; @lineHeight; @headingColor; @headingMarginBottom;) {
margin-bottom: @headingMarginBottom;
color: @headingColor;
font-weight: @fontWeight;
font-size: @fontSize;
line-height: @lineHeight;
}
.typography-title-1() {
.typography-title(
@heading-1-size,
@typography-title-font-weight,
1.23,
@heading-color,
@typography-title-margin-bottom
);
}
.typography-title-2() {
.typography-title(
@heading-2-size,
@typography-title-font-weight,
1.35,
@heading-color,
@typography-title-margin-bottom
);
}
.typography-title-3() {
.typography-title(
@heading-3-size,
@typography-title-font-weight,
1.35,
@heading-color,
@typography-title-margin-bottom
);
}
.typography-title-4() {
.typography-title(
@heading-4-size,
@typography-title-font-weight,
1.4,
@heading-color,
@typography-title-margin-bottom
);
}
.typography-title-5() {
.typography-title(
@heading-5-size,
@typography-title-font-weight,
1.5,
@heading-color,
@typography-title-margin-bottom
);
}

View File

@@ -1,295 +0,0 @@
@import './default.less';
@line-height-base: 1.66667;
@mode: compact;
@font-size-base: 12px;
@font-size-lg: @font-size-base + 2px;
// default paddings
@default-padding-lg: 24px; // containers
@default-padding-md: 16px; // small containers and buttons
@default-padding-sm: 12px; // Form controls and items
@default-padding-xs: 8px; // small items
@default-padding-xss: 4px; // more small
// vertical paddings
@padding-lg: 16px; // containers
@padding-md: 8px; // small containers and buttons
@padding-sm: 8px; // Form controls and items
@padding-xs: 4px; // small items
@padding-xss: 0px; // more small
// vertical padding for all form controls
@control-padding-horizontal: @padding-sm;
@control-padding-horizontal-sm: @default-padding-xs;
// vertical margins
@margin-lg: 16px; // containers
@margin-md: 8px; // small containers and buttons
@margin-sm: 8px; // Form controls and items
@margin-xs: 4px; // small items
@margin-xss: 0px; // more small
// height rules
@height-base: 28px;
@height-lg: 32px;
@height-sm: 22px;
// Button
// ---
@btn-padding-horizontal-base: @default-padding-sm - 1px;
@btn-padding-horizontal-lg: @btn-padding-horizontal-base;
@btn-padding-horizontal-sm: @default-padding-xs - 1px;
@btn-square-only-icon-size-lg: 16px;
@btn-square-only-icon-size: 14px;
@btn-square-only-icon-size-sm: 12px;
// Breadcrumb
// ---
@breadcrumb-font-size: @font-size-base;
@breadcrumb-icon-font-size: @font-size-base;
//Dropdown
@dropdown-line-height: 18px;
// Menu
@menu-item-padding-horizontal: 12px;
@menu-horizontal-line-height: 38px;
@menu-inline-toplevel-item-height: 32px;
@menu-item-height: 32px;
@menu-item-vertical-margin: 0px;
@menu-item-boundary-margin: 0px;
@menu-icon-margin-right: 8px;
// Checkbox
@checkbox-size: 14px;
@checkbox-group-item-margin-right: 6px;
// picker
@picker-panel-cell-height: 22px;
@picker-panel-cell-width: 32px;
@picker-text-height: 32px;
@picker-time-panel-cell-height: 24px;
@picker-panel-without-time-cell-height: 48px;
// Form
// ---
@form-item-margin-bottom: 16px;
@form-vertical-label-padding: 0 0 4px;
// Rate
// ---
@rate-star-size: 16px;
// Radio
// ---
@radio-size: 14px;
@radio-wrapper-margin-right: 6px;
// Switch
// ---
@switch-height: 20px;
@switch-sm-height: 14px;
@switch-min-width: 40px;
@switch-sm-min-width: 24px;
@switch-inner-margin-min: 4px;
@switch-inner-margin-max: 22px;
// Slider
// ---
@slider-handle-size: 12px;
@slider-handle-margin-top: -4px;
// Input
// ---
@input-padding-vertical-base: round(
max(
(round(((@input-height-base - @font-size-base * @line-height-base) / 2) * 10) / 10) -
@border-width-base,
2px
)
);
@input-padding-horizontal-lg: 11px;
// PageHeader
// ---
@page-header-padding: 16px;
@page-header-padding-vertical: 8px;
@page-header-heading-title: 16px;
@page-header-heading-sub-title: 12px;
@page-header-tabs-tab-font-size: 14px;
// Pagination
// ---
@pagination-mini-options-size-changer-top: 1px;
@pagination-item-size-sm: 22px;
// Cascader
// ----
@cascader-dropdown-line-height: @dropdown-line-height;
// Select
// ---
@select-dropdown-height: @height-base;
@select-single-item-height-lg: 32px;
@select-multiple-item-height: @input-height-base - max(@input-padding-vertical-base, 4) * 2; // Normal 24px
@select-multiple-item-height-lg: 24px;
@select-multiple-item-spacing-half: 3px;
// Tree
// ---
@tree-title-height: 20px;
// Transfer
// ---
@transfer-item-padding-vertical: 3px;
@transfer-list-search-icon-top: 8px;
@transfer-header-height: 36px;
// Comment
// ---
@comment-actions-margin-bottom: 0px;
@comment-actions-margin-top: @margin-xs;
@comment-content-detail-p-margin-bottom: 0px;
// Steps
// ---
@steps-icon-size: 24px;
@steps-icon-custom-size: 20px;
@steps-icon-custom-font-size: 20px;
@steps-icon-custom-top: 2px;
@steps-icon-margin: 2px 8px 2px 0;
@steps-icon-font-size: @font-size-base;
@steps-dot-top: 4px;
@steps-icon-top: 0px;
@steps-small-icon-size: 20px;
@steps-vertical-icon-width: 12px;
@steps-vertical-tail-width: 12px;
@steps-vertical-tail-width-sm: 10px;
// Collapse
// ---
//@collapse-header-padding-extra: 32px;
@collapse-content-padding: @padding-md @padding-lg;
// List
// ---
@list-item-meta-description-font-size: @font-size-sm;
@list-item-padding-sm: 4px 12px;
@list-item-padding-lg: 12px 16px;
// Drawer
// ---
@drawer-header-padding: 11px @padding-lg;
@drawer-footer-padding-vertical: @padding-sm;
@drawer-footer-padding-horizontal: @padding-sm;
@drawer-header-close-size: 44px;
// Modal
// --
@modal-header-padding-vertical: 11px;
@modal-header-padding: @modal-header-padding-vertical @modal-header-padding-horizontal;
@modal-footer-padding-vertical: @padding-sm;
@modal-header-close-size: @modal-header-title-line-height + 2 * @modal-header-padding-vertical;
@modal-confirm-body-padding: 24px 24px 16px;
// Message
// ---
@message-notice-content-padding: 8px 16px;
// popover
// --
@popover-min-height: 28px;
@popover-padding-horizontal: @default-padding-sm;
// Card
// ---
@card-head-height: 36px;
@card-head-font-size: @card-head-font-size-sm;
@card-head-padding: 8.5px;
@card-padding-base: 12px;
@card-padding-base-sm: @card-padding-base;
@card-head-height-sm: 30px;
@card-head-padding-sm: 6px;
@card-actions-li-margin: 4px 0;
@card-head-tabs-margin-bottom: -9px;
// Table
// ---
@table-padding-vertical: 12px;
@table-padding-horizontal: 8px;
@table-padding-vertical-md: 8px;
@table-padding-horizontal-md: 8px;
@table-padding-vertical-sm: 4px;
@table-padding-horizontal-sm: 4px;
@table-selection-column-width: 32px;
// Statistic
// ---
@statistic-content-font-size: 20px;
// Alert
// ---
@alert-with-description-no-icon-padding-vertical: 7px;
@alert-with-description-padding-vertical: 11px;
@alert-icon-top: 7px + @font-size-base * (@line-height-base / 2) - (@font-size-base / 2);
@alert-with-description-icon-size: 20px;
// Skeleton
// ---
@skeleton-paragraph-margin-top: 20px;
@skeleton-paragraph-li-margin-top: 12px;
@skeleton-paragraph-li-height: 14px;
@skeleton-title-height: 14px;
@skeleton-title-paragraph-margin-top: 20px;
// Descriptions
@descriptions-title-margin-bottom: 8px;
@descriptions-default-padding: 12px @padding-lg;
@descriptions-item-padding-bottom: @padding-xs;
// Avatar
// ---
@avatar-size-base: 28px;
@avatar-size-lg: 32px;
@avatar-size-sm: 22px;
@avatar-font-size-base: 16px;
@avatar-font-size-lg: 20px;
@avatar-font-size-sm: 12px;
// Badge
// ---
@badge-height: 18px;
// Tag
// ---
@tag-line-height: 18px;
// Notification
// ---
@notification-padding-vertical: 12px;
@notification-padding-horizontal: 16px;
// Result
// ---
@result-title-font-size: 20px;
@result-icon-font-size: 64px;
@result-extra-margin: 24px 0 0 0;
// Anchor
// ---
@anchor-link-top: 4px;
@anchor-link-left: 16px;
@anchor-link-padding: @anchor-link-top 0 @anchor-link-top @anchor-link-left;
// Tabs
// ---
@tabs-card-horizontal-padding: 4px @padding-md;
// Progress
// ---
@progress-circle-text-font-size: 0.833333em;
// Image
// ---
@image-size-base: 48px;
@image-font-size-base: 24px;

View File

@@ -1,457 +0,0 @@
@import './default.less';
@theme: dark;
// color palettes
@blue-1: mix(color(~`colorPalette('@{blue-base}', 8) `), @component-background, 15%);
@blue-2: mix(color(~`colorPalette('@{blue-base}', 7) `), @component-background, 25%);
@blue-3: mix(@blue-base, @component-background, 30%);
@blue-4: mix(@blue-base, @component-background, 45%);
@blue-5: mix(@blue-base, @component-background, 65%);
@blue-6: mix(@blue-base, @component-background, 85%);
@blue-7: mix(color(~`colorPalette('@{blue-base}', 5) `), @component-background, 90%);
@blue-8: mix(color(~`colorPalette('@{blue-base}', 4) `), @component-background, 95%);
@blue-9: mix(color(~`colorPalette('@{blue-base}', 3) `), @component-background, 97%);
@blue-10: mix(color(~`colorPalette('@{blue-base}', 2) `), @component-background, 98%);
@purple-1: mix(color(~`colorPalette('@{purple-base}', 8) `), @component-background, 15%);
@purple-2: mix(color(~`colorPalette('@{purple-base}', 7) `), @component-background, 25%);
@purple-3: mix(@purple-base, @component-background, 30%);
@purple-4: mix(@purple-base, @component-background, 45%);
@purple-5: mix(@purple-base, @component-background, 65%);
@purple-6: mix(@purple-base, @component-background, 85%);
@purple-7: mix(color(~`colorPalette('@{purple-base}', 5) `), @component-background, 90%);
@purple-8: mix(color(~`colorPalette('@{purple-base}', 4) `), @component-background, 95%);
@purple-9: mix(color(~`colorPalette('@{purple-base}', 3) `), @component-background, 97%);
@purple-10: mix(color(~`colorPalette('@{purple-base}', 2) `), @component-background, 98%);
@cyan-1: mix(color(~`colorPalette('@{cyan-base}', 8) `), @component-background, 15%);
@cyan-2: mix(color(~`colorPalette('@{cyan-base}', 7) `), @component-background, 25%);
@cyan-3: mix(@cyan-base, @component-background, 30%);
@cyan-4: mix(@cyan-base, @component-background, 45%);
@cyan-5: mix(@cyan-base, @component-background, 65%);
@cyan-6: mix(@cyan-base, @component-background, 85%);
@cyan-7: mix(color(~`colorPalette('@{cyan-base}', 5) `), @component-background, 90%);
@cyan-8: mix(color(~`colorPalette('@{cyan-base}', 4) `), @component-background, 95%);
@cyan-9: mix(color(~`colorPalette('@{cyan-base}', 3) `), @component-background, 97%);
@cyan-10: mix(color(~`colorPalette('@{cyan-base}', 2) `), @component-background, 98%);
@green-1: mix(color(~`colorPalette('@{green-base}', 8) `), @component-background, 15%);
@green-2: mix(color(~`colorPalette('@{green-base}', 7) `), @component-background, 25%);
@green-3: mix(@green-base, @component-background, 30%);
@green-4: mix(@green-base, @component-background, 45%);
@green-5: mix(@green-base, @component-background, 65%);
@green-6: mix(@green-base, @component-background, 85%);
@green-7: mix(color(~`colorPalette('@{green-base}', 5) `), @component-background, 90%);
@green-8: mix(color(~`colorPalette('@{green-base}', 4) `), @component-background, 95%);
@green-9: mix(color(~`colorPalette('@{green-base}', 3) `), @component-background, 97%);
@green-10: mix(color(~`colorPalette('@{green-base}', 2) `), @component-background, 98%);
@magenta-1: mix(color(~`colorPalette('@{magenta-base}', 8) `), @component-background, 15%);
@magenta-2: mix(color(~`colorPalette('@{magenta-base}', 7) `), @component-background, 25%);
@magenta-3: mix(@magenta-base, @component-background, 30%);
@magenta-4: mix(@magenta-base, @component-background, 45%);
@magenta-5: mix(@magenta-base, @component-background, 65%);
@magenta-6: mix(@magenta-base, @component-background, 85%);
@magenta-7: mix(color(~`colorPalette('@{magenta-base}', 5) `), @component-background, 90%);
@magenta-8: mix(color(~`colorPalette('@{magenta-base}', 4) `), @component-background, 95%);
@magenta-9: mix(color(~`colorPalette('@{magenta-base}', 3) `), @component-background, 97%);
@magenta-10: mix(color(~`colorPalette('@{magenta-base}', 2) `), @component-background, 98%);
@pink-1: mix(color(~`colorPalette('@{pink-base}', 8) `), @component-background, 15%);
@pink-2: mix(color(~`colorPalette('@{pink-base}', 7) `), @component-background, 25%);
@pink-3: mix(@pink-base, @component-background, 30%);
@pink-4: mix(@pink-base, @component-background, 45%);
@pink-5: mix(@pink-base, @component-background, 65%);
@pink-6: mix(@pink-base, @component-background, 85%);
@pink-7: mix(color(~`colorPalette('@{pink-base}', 5) `), @component-background, 90%);
@pink-8: mix(color(~`colorPalette('@{pink-base}', 4) `), @component-background, 95%);
@pink-9: mix(color(~`colorPalette('@{pink-base}', 3) `), @component-background, 97%);
@pink-10: mix(color(~`colorPalette('@{pink-base}', 2) `), @component-background, 98%);
@red-1: mix(color(~`colorPalette('@{red-base}', 8) `), @component-background, 15%);
@red-2: mix(color(~`colorPalette('@{red-base}', 7) `), @component-background, 25%);
@red-3: mix(@red-base, @component-background, 30%);
@red-4: mix(@red-base, @component-background, 45%);
@red-5: mix(@red-base, @component-background, 65%);
@red-6: mix(@red-base, @component-background, 85%);
@red-7: mix(color(~`colorPalette('@{red-base}', 5) `), @component-background, 90%);
@red-8: mix(color(~`colorPalette('@{red-base}', 4) `), @component-background, 95%);
@red-9: mix(color(~`colorPalette('@{red-base}', 3) `), @component-background, 97%);
@red-10: mix(color(~`colorPalette('@{red-base}', 2) `), @component-background, 98%);
@orange-1: mix(color(~`colorPalette('@{orange-base}', 8) `), @component-background, 15%);
@orange-2: mix(color(~`colorPalette('@{orange-base}', 7) `), @component-background, 25%);
@orange-3: mix(@orange-base, @component-background, 30%);
@orange-4: mix(@orange-base, @component-background, 45%);
@orange-5: mix(@orange-base, @component-background, 65%);
@orange-6: mix(@orange-base, @component-background, 85%);
@orange-7: mix(color(~`colorPalette('@{orange-base}', 5) `), @component-background, 90%);
@orange-8: mix(color(~`colorPalette('@{orange-base}', 4) `), @component-background, 95%);
@orange-9: mix(color(~`colorPalette('@{orange-base}', 3) `), @component-background, 97%);
@orange-10: mix(color(~`colorPalette('@{orange-base}', 2) `), @component-background, 98%);
@yellow-1: mix(color(~`colorPalette('@{yellow-base}', 8) `), @component-background, 15%);
@yellow-2: mix(color(~`colorPalette('@{yellow-base}', 7) `), @component-background, 25%);
@yellow-3: mix(@yellow-base, @component-background, 30%);
@yellow-4: mix(@yellow-base, @component-background, 45%);
@yellow-5: mix(@yellow-base, @component-background, 65%);
@yellow-6: mix(@yellow-base, @component-background, 85%);
@yellow-7: mix(color(~`colorPalette('@{yellow-base}', 5) `), @component-background, 90%);
@yellow-8: mix(color(~`colorPalette('@{yellow-base}', 4) `), @component-background, 95%);
@yellow-9: mix(color(~`colorPalette('@{yellow-base}', 3) `), @component-background, 97%);
@yellow-10: mix(color(~`colorPalette('@{yellow-base}', 2) `), @component-background, 98%);
@volcano-1: mix(color(~`colorPalette('@{volcano-base}', 8) `), @component-background, 15%);
@volcano-2: mix(color(~`colorPalette('@{volcano-base}', 7) `), @component-background, 25%);
@volcano-3: mix(@volcano-base, @component-background, 30%);
@volcano-4: mix(@volcano-base, @component-background, 45%);
@volcano-5: mix(@volcano-base, @component-background, 65%);
@volcano-6: mix(@volcano-base, @component-background, 85%);
@volcano-7: mix(color(~`colorPalette('@{volcano-base}', 5) `), @component-background, 90%);
@volcano-8: mix(color(~`colorPalette('@{volcano-base}', 4) `), @component-background, 95%);
@volcano-9: mix(color(~`colorPalette('@{volcano-base}', 3) `), @component-background, 97%);
@volcano-10: mix(color(~`colorPalette('@{volcano-base}', 2) `), @component-background, 98%);
@geekblue-1: mix(color(~`colorPalette('@{geekblue-base}', 8) `), @component-background, 15%);
@geekblue-2: mix(color(~`colorPalette('@{geekblue-base}', 7) `), @component-background, 25%);
@geekblue-3: mix(@geekblue-base, @component-background, 30%);
@geekblue-4: mix(@geekblue-base, @component-background, 45%);
@geekblue-5: mix(@geekblue-base, @component-background, 65%);
@geekblue-6: mix(@geekblue-base, @component-background, 85%);
@geekblue-7: mix(color(~`colorPalette('@{geekblue-base}', 5) `), @component-background, 90%);
@geekblue-8: mix(color(~`colorPalette('@{geekblue-base}', 4) `), @component-background, 95%);
@geekblue-9: mix(color(~`colorPalette('@{geekblue-base}', 3) `), @component-background, 97%);
@geekblue-10: mix(color(~`colorPalette('@{geekblue-base}', 2) `), @component-background, 98%);
@lime-1: mix(color(~`colorPalette('@{lime-base}', 8) `), @component-background, 15%);
@lime-2: mix(color(~`colorPalette('@{lime-base}', 7) `), @component-background, 25%);
@lime-3: mix(@lime-base, @component-background, 30%);
@lime-4: mix(@lime-base, @component-background, 45%);
@lime-5: mix(@lime-base, @component-background, 65%);
@lime-6: mix(@lime-base, @component-background, 85%);
@lime-7: mix(color(~`colorPalette('@{lime-base}', 5) `), @component-background, 90%);
@lime-8: mix(color(~`colorPalette('@{lime-base}', 4) `), @component-background, 95%);
@lime-9: mix(color(~`colorPalette('@{lime-base}', 3) `), @component-background, 97%);
@lime-10: mix(color(~`colorPalette('@{lime-base}', 2) `), @component-background, 98%);
@gold-1: mix(color(~`colorPalette('@{gold-base}', 8) `), @component-background, 15%);
@gold-2: mix(color(~`colorPalette('@{gold-base}', 7) `), @component-background, 25%);
@gold-3: mix(@gold-base, @component-background, 30%);
@gold-4: mix(@gold-base, @component-background, 45%);
@gold-5: mix(@gold-base, @component-background, 65%);
@gold-6: mix(@gold-base, @component-background, 85%);
@gold-7: mix(color(~`colorPalette('@{gold-base}', 5) `), @component-background, 90%);
@gold-8: mix(color(~`colorPalette('@{gold-base}', 4) `), @component-background, 95%);
@gold-9: mix(color(~`colorPalette('@{gold-base}', 3) `), @component-background, 97%);
@gold-10: mix(color(~`colorPalette('@{gold-base}', 2) `), @component-background, 98%);
// Color used by default to control hover and active backgrounds and for
// alert info backgrounds.
@primary-1: mix(color(~`colorPalette('@{primary-color}', 8) `), @component-background, 15%);
@primary-2: mix(color(~`colorPalette('@{primary-color}', 7) `), @component-background, 25%);
@primary-3: mix(@primary-color, @component-background, 30%);
@primary-4: mix(@primary-color, @component-background, 45%);
@primary-5: mix(@primary-color, @component-background, 65%);
@primary-6: @primary-color;
@primary-7: mix(color(~`colorPalette('@{primary-color}', 5) `), @component-background, 90%);
@primary-8: mix(color(~`colorPalette('@{primary-color}', 4) `), @component-background, 95%);
@primary-9: mix(color(~`colorPalette('@{primary-color}', 3) `), @component-background, 97%);
@primary-10: mix(color(~`colorPalette('@{primary-color}', 2) `), @component-background, 98%);
// Layer background
@popover-background: #1f1f1f;
@popover-customize-border-color: #3a3a3a;
@body-background: @black;
@component-background: #141414;
@text-color: fade(@white, 85%);
@text-color-secondary: fade(@white, 45%);
@text-color-inverse: @white;
@icon-color-hover: fade(@white, 75%);
@heading-color: fade(@white, 85%);
// The background colors for active and hover states for things like
// list items or table cells.
@item-active-bg: @primary-1;
@item-hover-bg: fade(@white, 8%);
// Border color
@border-color-base: #434343; // base border outline a component
@border-color-split: #303030; // split border inside a component
@background-color-light: fade(@white, 4%); // background of header and selected item
@background-color-base: fade(@white, 8%); // Default grey background color
// Disabled states
@disabled-color: fade(@white, 30%);
@disabled-bg: @background-color-base;
@disabled-color-dark: fade(@white, 30%);
// Tree
// ---
@tree-bg: transparent;
// List
// ---
@list-customize-card-bg: transparent;
// Shadow
// ---
@shadow-color: rgba(0, 0, 0, 0.45);
@shadow-color-inverse: @component-background;
@box-shadow-base: @shadow-2;
@shadow-1-up: 0 -6px 16px -8px rgba(0, 0, 0, 0.32), 0 -9px 28px 0 rgba(0, 0, 0, 0.2),
0 -12px 48px 16px rgba(0, 0, 0, 0.12);
@shadow-1-down: 0 6px 16px -8px rgba(0, 0, 0, 0.32), 0 9px 28px 0 rgba(0, 0, 0, 0.2),
0 12px 48px 16px rgba(0, 0, 0, 0.12);
@shadow-1-right: 6px 0 16px -8px rgba(0, 0, 0, 0.32), 9px 0 28px 0 rgba(0, 0, 0, 0.2),
12px 0 48px 16px rgba(0, 0, 0, 0.12);
@shadow-2: 0 3px 6px -4px rgba(0, 0, 0, 0.48), 0 6px 16px 0 rgba(0, 0, 0, 0.32),
0 9px 28px 8px rgba(0, 0, 0, 0.2);
// Buttons
// ---
@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
@btn-default-bg: transparent;
@btn-default-ghost-color: @text-color;
@btn-default-ghost-border: fade(@white, 25%);
@btn-text-hover-bg: rgba(255, 255, 255, 0.03);
// Checkbox
// ---
@checkbox-check-bg: transparent;
// Descriptions
// ---
@descriptions-bg: @background-color-light;
// Divider
// ---
@divider-color: rgba(255, 255, 255, 12%);
// Modal
// ---
@modal-header-bg: @popover-background;
@modal-header-border-color-split: @border-color-split;
@modal-content-bg: @popover-background;
@modal-footer-border-color-split: @border-color-split;
// Radio
// ---
@radio-solid-checked-color: @white;
@radio-dot-disabled-color: fade(@white, 20%);
// Radio buttons
// ---
@radio-disabled-button-checked-bg: fade(@white, 20%);
@radio-disabled-button-checked-color: @disabled-color;
// Layout
// ---
@layout-body-background: @body-background;
@layout-header-background: @popover-background;
@layout-trigger-background: #262626;
// Input
// ---
@input-bg: transparent;
@input-placeholder-color: fade(@white, 30%);
@input-icon-color: fade(@white, 30%);
@input-number-handler-active-bg: @item-hover-bg;
@input-icon-hover-color: fade(@white, 85%);
// Select
// ---
@select-background: transparent;
@select-dropdown-bg: @popover-background;
@select-clear-background: @component-background;
@select-selection-item-bg: fade(@white, 8);
@select-selection-item-border-color: @border-color-split;
@select-multiple-disabled-background: @component-background;
@select-multiple-item-disabled-color: #595959;
@select-multiple-item-disabled-border-color: @popover-background;
// Cascader
// ---
@cascader-bg: transparent;
@cascader-menu-bg: @popover-background;
@cascader-menu-border-color-split: @border-color-split;
// Tooltip
// ---
// Tooltip background color
@tooltip-bg: #434343;
// Menu
// ---
// dark theme
@menu-dark-inline-submenu-bg: @component-background;
@menu-dark-bg: @popover-background;
@menu-popup-bg: @popover-background;
// Message
// ---
@message-notice-content-bg: @popover-background;
// Notification
@notification-bg: @popover-background;
// LINK
@link-hover-color: @primary-5;
@link-active-color: @primary-7;
// Table
// --
@table-header-bg: #1d1d1d;
@table-body-sort-bg: fade(@white, 1%);
@table-row-hover-bg: #262626;
@table-header-cell-split-color: fade(@white, 8%);
@table-header-sort-bg: #262626;
@table-header-filter-active-bg: #434343;
@table-header-sort-active-bg: #303030;
@table-fixed-header-sort-active-bg: #222;
@table-filter-btns-bg: @popover-background;
@table-expanded-row-bg: @table-header-bg;
@table-filter-dropdown-bg: @popover-background;
@table-expand-icon-bg: transparent;
// Tag
// ---
@info-color-deprecated-bg: @primary-1;
@info-color-deprecated-border: @primary-3;
@success-color-deprecated-bg: @green-1;
@success-color-deprecated-border: @green-3;
@warning-color-deprecated-bg: @orange-1;
@warning-color-deprecated-border: @orange-3;
@error-color-deprecated-bg: @red-1;
@error-color-deprecated-border: @red-3;
// TimePicker
// ---
@picker-basic-cell-hover-with-range-color: darken(@primary-color, 35%);
@picker-basic-cell-disabled-bg: #303030;
@picker-border-color: @border-color-split;
@picker-bg: transparent;
@picker-date-hover-range-border-color: darken(@primary-color, 20%);
// Dropdown
// ---
@dropdown-menu-bg: @popover-background;
@dropdown-menu-submenu-disabled-bg: transparent;
// Steps
// ---
@steps-nav-arrow-color: fade(@white, 20%);
@steps-background: transparent;
// Avatar
// ---
@avatar-bg: fade(@white, 30%);
// Progress
// ---
@progress-steps-item-bg: fade(@white, 8%);
// Calendar
// ---
@calendar-bg: @popover-background;
@calendar-input-bg: @calendar-bg;
@calendar-border-color: transparent;
@calendar-full-bg: @component-background;
// Badge
// ---
@badge-text-color: @white;
// Popover
@popover-bg: @popover-background;
// Drawer
@drawer-bg: @popover-background;
// Card
// ---
@card-actions-background: @component-background;
@card-skeleton-bg: #303030;
@card-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.64), 0 3px 6px 0 rgba(0, 0, 0, 0.48),
0 5px 12px 4px rgba(0, 0, 0, 0.36);
// Transfer
// ---
@transfer-item-hover-bg: #262626;
// Comment
// ---
@comment-bg: transparent;
@comment-author-time-color: fade(@white, 30%);
@comment-action-hover-color: fade(@white, 65%);
// Rate
// ---
@rate-star-bg: fade(@white, 12%);
// Switch
// ---
@switch-bg: @white;
// Pagination
// ---
@pagination-item-bg: transparent;
@pagination-item-bg-active: transparent;
@pagination-item-link-bg: transparent;
@pagination-item-disabled-bg-active: fade(@white, 25%);
@pagination-item-disabled-color-active: @black;
@pagination-item-input-bg: @pagination-item-bg;
// PageHeader
// ---
@page-header-back-color: @icon-color;
@page-header-ghost-bg: transparent;
// Slider
// ---
@slider-rail-background-color: #262626;
@slider-rail-background-color-hover: @border-color-base;
@slider-dot-border-color: @border-color-split;
@slider-dot-border-color-active: @primary-4;
// Skeleton
// ---
@skeleton-to-color: fade(@white, 16%);
// Alert
// ---
@alert-success-border-color: @green-3;
@alert-success-bg-color: @green-1;
@alert-success-icon-color: @success-color;
@alert-info-border-color: @primary-3;
@alert-info-bg-color: @primary-1;
@alert-info-icon-color: @info-color;
@alert-warning-border-color: @gold-3;
@alert-warning-bg-color: @gold-1;
@alert-warning-icon-color: @warning-color;
@alert-error-border-color: @red-3;
@alert-error-bg-color: @red-1;
@alert-error-icon-color: @error-color;
// Timeline
// ---
@timeline-color: @border-color-split;
@timeline-dot-color: @primary-color;
// Mentions
// ---
@mentions-dropdown-bg: @popover-background;
// Segmented
// ---
@segmented-bg: fade(@black, 25%);
@segmented-hover-bg: fade(@black, 45%);
@segmented-selected-bg: #333333;
@segmented-label-color: fade(@white, 65%);
@segmented-label-hover-color: fade(@white, 85%);

View File

@@ -1,7 +0,0 @@
// Default using variable as entry to support site variable version
// This will be replaced in webpack bundle
// @root-entry-name: variable;
// @import './default.less';
// @import './variable.less';
@import './@{root-entry-name}.less';

View File

@@ -1,4 +0,0 @@
@root-entry-name: variable;
@import './themes/variable.less';
@import './core/index';

View File

@@ -7,6 +7,7 @@ import {
DeleteOutlined,
ExportOutlined,
RocketOutlined,
FormOutlined,
} from '@ant-design/icons';
export type BatchCtrlDropDownButtonProps = {
@@ -52,6 +53,12 @@ const BatchCtrlDropDownButton: FC<BatchCtrlDropDownButtonProps> = ({
icon: <RocketOutlined />,
disabled: disabledList?.includes('batchUnPublish'),
},
batchAddClass: {
key: 'batchAddClass',
label: '批量分类',
icon: <FormOutlined />,
disabled: disabledList?.includes('batchAddClass'),
},
};
const extenderButtonList: any[] = extenderList.reduce((list: any[], key) => {

View File

@@ -18,7 +18,7 @@ const FormItemTitle: React.FC<IProps> = ({
}) => {
return (
<Space direction="vertical" size={2} style={{ width: '100%' }}>
<div>{title}</div>
<div className={styles.title}>{title}</div>
<div className={styles.subTitleContainer}>
{subTitleEditable ? (
<Paragraph
@@ -31,7 +31,7 @@ const FormItemTitle: React.FC<IProps> = ({
{subTitle || '添加描述'}
</Paragraph>
) : (
subTitle && <span style={{ fontSize: '12px', color: '#6a6a6a' }}>{subTitle}</span>
subTitle && <span style={{ fontSize: '12px', color: '#7b809a' }}>{subTitle}</span>
)}
</div>
</Space>

View File

@@ -1,5 +1,11 @@
.title {
font-family: var(--tencent-font-family);
margin-bottom: 5px;
}
.subTitleContainer {
width: 500px;
color: #7b809a;
:global {
.ant-typography{
font-size: 12px;

View File

@@ -51,7 +51,7 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = () => {
<HeaderDropdown menu={{ items }} disabled={APP_TARGET === 'inner'}>
<span className={`${styles.action} ${styles.account}`}>
<TMEAvatar className={styles.avatar} size="small" staffName={currentUser.staffName} />
<span style={{ color: '#fff' }}>{currentUser.staffName}</span>
<span className={styles.userName}>{currentUser.staffName}</span>
</span>
</HeaderDropdown>
);

View File

@@ -27,19 +27,21 @@
cursor: pointer;
transition: all 0.3s;
color: #fff;
margin-right: 10px;
>span {
vertical-align: middle;
}
&:hover {
background: #296df3;
background: rgba(232, 232, 232, 0.65);
border-radius: 8px;
}
&:global(.opened) {
background: @pro-header-hover-bg;
}
// &:global(.opened) {
// background: @pro-header-hover-bg;
// }
}
.search {
@@ -53,9 +55,13 @@
.account {
.avatar {
margin-right: 8px;
color: @primary-color;
color: var(--tme-primary-color);
vertical-align: top;
background: rgba(255, 255, 255, 0.85);
background: rgba(150, 150, 150, 0.85);
}
.userName {
color: var(--tme-primary-color);
font-family: var(--tencent-font-family);
}
}
}

View File

@@ -1,11 +1,9 @@
import { useState } from 'react';
import { useState, useEffect } from 'react';
import type { FC } from 'react';
import { Select, message } from 'antd';
import { Select } from 'antd';
import type { UserItem } from './service';
import { getAllUser } from './service';
import { useModel } from '@umijs/max';
import styles from './index.less';
import { useFetchDataEffect } from '@/utils/curd';
import TMEAvatar from '../TMEAvatar';
interface Props {
@@ -17,27 +15,20 @@ interface Props {
const SelectTMEPerson: FC<Props> = ({ placeholder, value, isMultiple = true, onChange }) => {
const [userList, setUserList] = useState<UserItem[]>([]);
const allUserModel = useModel('allUserData');
const { allUserList, MrefreshUserList } = allUserModel;
useFetchDataEffect(
{
fetcher: async () => {
const res = await getAllUser();
if (res.code == 200 || Number(res.code) == 0) {
return res.data || [];
} else {
message.error(res.msg);
throw new Error(res.msg);
}
},
updater: (list) => {
const queryTmePersonData = async () => {
const list = await MrefreshUserList();
setUserList(list);
},
cleanup: () => {
setUserList([]);
},
},
[],
);
};
useEffect(() => {
if (Array.isArray(allUserList) && allUserList.length > 0) {
setUserList(allUserList);
} else {
queryTmePersonData();
}
}, []);
return (
<Select

View File

@@ -1,8 +1,3 @@
export const EnumTransModelType = {
edit: '编辑',
add: '新增',
};
export const EnumDescSensitivity = {
low: {
value: 1,

View File

@@ -1,7 +1,7 @@
:root:root {
--primary-color: #f87653;
--tme-primary-color: #1672fa;
--blue: #296df3;
--deep-blue: #446dff;
--chat-blue: #1b4aef;
@@ -22,13 +22,15 @@
--processing-color: #ff2442;
--error-color: #ff4d4f;
--highlight-color: #ff4d4f;
--font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Microsoft YaHei,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
--tencent-font-family: 'tencentFont',-apple-system,BlinkMacSystemFont,"Segoe UI",Microsoft YaHei,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
}
html,
body,
#root {
height: 100%;
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Microsoft YaHei,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
font-family: var(--tencent-font-family);
-webkit-font-smoothing:antialiased;
margin: 0;
}
@@ -56,6 +58,16 @@ ol {
list-style: none;
}
@font-face {
font-family: 'DINPro Medium';
src: url('~@/assets/fonts/DINPro.woff2') format('woff2');
}
@font-face {
font-family: 'tencentFont';
src: url('~@/assets/fonts/TencentSans-W7.woff') format('woff');
}
@media (max-width: 480px) {
.ant-table {
width: 100%;
@@ -96,9 +108,9 @@ ol {
margin: 12px 12px 0 !important;
}
.ant-page-header {
padding-bottom: 10px !important;
}
// .ant-page-header {
// padding-bottom: 10px !important;
// }
.ant-spin-spinning {
display: flex !important;
@@ -120,10 +132,12 @@ ol {
height: 100vh;
}
}
.ant-pro-layout .ant-pro-layout-bg-list {
background: #fafafb;
}
.ant-pro-layout .ant-pro-layout-content {
padding: 0;
background-color: #f0f2f5;
background-color: #fafafb;
}
@@ -132,51 +146,55 @@ ol {
text-overflow: ellipsis;
}
.ant-pro-top-nav-header-menu {
padding: 0!important;
line-height: unset!important;
}
.ant-menu-root>.ant-menu-item,
.ant-menu-root>.ant-menu-submenu {
font-weight: bold;
font-size: 14px;
&>span>a,
&>a {
color: white;
&:hover {
color: white;
}
}
&:hover {
background-color: #296DF3!important;
}
}
// .ant-menu-root>.ant-menu-item,
// .ant-menu-root>.ant-menu-submenu {
// font-weight: bold;
// font-size: 14px;
// &>span>a,
// &>a {
// color: white;
// &:hover {
// color: white;
// }
// }
// &:hover {
// background-color: #296DF3!important;
// }
// }
.ant-menu-root>.ant-menu-item.ant-menu-item-selected {
background-color: #296DF3!important;
color: white;
// background-color: #296DF3!important;
color: var(--tme-primary-color);
font-size: 15px;
font-weight: 500;
}
.ant-menu-light.ant-menu-horizontal >.ant-menu-item-selected::after {
border-bottom-width: 2px;
border-bottom-color: var(--tme-primary-color);
}
// .ant-menu-light.ant-menu-horizontal >.ant-menu-item-selected::hover {
// border-bottom-width: 2px;
// border-bottom-color: var(--tme-primary-color);
// }
.ant-pro-top-nav-header-logo h1 {
font-size: 18px;
}
.ant-layout-header {
background: linear-gradient(to right, #153d8f, #0a276d) !important;
background-color: rgba(0, 0, 0, 0.2) !important;
backdrop-filter: blur(10px) !important;
// font-size: 18px;
color: var(--tme-primary-color)
}
.ant-pro-top-nav-header-main-left {
min-width: 100px !important;
}
.ant-pro-top-nav-header-logo {
min-width: 100px !important;
}
// .ant-pro-top-nav-header-main-left {
// min-width: 100px !important;
// }
// .ant-pro-top-nav-header-logo {
// min-width: 100px !important;
// }
.logo {
@@ -240,3 +258,37 @@ ol {
font-weight: 500;
color: #667085;
}
.ant-select-dropdown {
.ant-select-item {
-webkit-tap-highlight-color: transparent;
background-color: transparent;
outline: 0px;
border: 0px;
margin: 0px;
border-radius: 0px;
cursor: pointer;
user-select: none;
vertical-align: middle;
appearance: none;
color: #606060;
font-size: 14px;
line-height: 1.57;
font-family: var(--tencent-font-family);
display: flex;
justify-content: flex-start;
align-items: center;
position: relative;
text-decoration: none;
min-height: 36px;
padding: 6px 16px;
box-sizing: border-box;
white-space: nowrap;
font-weight: 400;
}
&.ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
font-weight: 400;
color: rgb(38, 38, 38);
}
}

View File

@@ -10,6 +10,7 @@ export default {
'menu.semanticModel': '语义建模',
'menu.metric': '指标市场',
'menu.metric.metricDetail': '指标详情页',
'menu.metricEdit': '指标编辑',
'menu.tag': '标签市场',
'menu.tag.tagDetail': '标签详情页',
'menu.database': '数据库管理',

View File

@@ -0,0 +1,25 @@
import { useState } from 'react';
import { getAllUser } from '../components/SelectTMEPerson/service';
import type { UserItem } from '../components/SelectTMEPerson/service';
export default function Model() {
const [allUserList, setAllUserList] = useState<UserItem[]>([]);
const queryUserData = async () => {
const { code, data } = await getAllUser();
if (code === 200 || Number(code) === 0) {
setAllUserList(data);
return data;
}
return [];
};
const MrefreshUserList = async () => {
return await queryUserData();
};
return {
allUserList,
MrefreshUserList,
};
}

View File

@@ -1,10 +1,12 @@
import { useLocation } from 'umi';
import { useLocation } from '@umijs/max';
import { getToken } from '@/utils/utils';
import queryString from 'query-string';
import { Chat } from 'supersonic-chat-sdk';
const ChatPage = () => {
const location = useLocation();
const { agentId } = (location as any).query;
const query = queryString.parse(location.search) || {};
const { agentId } = query;
return (
<Chat initialAgentId={agentId ? +agentId : undefined} token={getToken() || ''} isDeveloper />

View File

@@ -12,23 +12,19 @@ import {
getUnAvailableItem,
getTagObjectList,
} from '../../service';
import type { Dispatch } from 'umi';
import type { StateType } from '../../model';
import { connect } from 'umi';
import { useModel } from '@umijs/max';
import { ISemantic, IDataSource } from '../../data';
import { isArrayOfValues } from '@/utils/utils';
import EffectDimensionAndMetricTipsModal from './EffectDimensionAndMetricTipsModal';
export type CreateFormProps = {
domainManger: StateType;
dispatch: Dispatch;
createModalVisible: boolean;
sql?: string;
sqlParams?: IDataSource.ISqlParamsItem[];
databaseId?: number;
modelItem: ISemantic.IModelItem;
onCancel?: () => void;
onSubmit?: (dataSourceInfo: any) => void;
onSubmit?: (modelItem: ISemantic.IModelItem) => void;
scriptColumns?: any[] | undefined;
basicInfoFormMode?: 'normal' | 'fast';
onDataBaseTableChange?: (tableName: string) => void;
@@ -44,7 +40,6 @@ const initFormVal = {
};
const ModelCreateForm: React.FC<CreateFormProps> = ({
domainManger,
onCancel,
createModalVisible,
scriptColumns,
@@ -63,7 +58,7 @@ const ModelCreateForm: React.FC<CreateFormProps> = ({
const [fields, setFields] = useState<any[]>([]);
const [currentStep, setCurrentStep] = useState(0);
const [saveLoading, setSaveLoading] = useState(false);
// const [hasEmptyNameField, setHasEmptyNameField] = useState<boolean>(false);
const [formDatabaseId, setFormDatabaseId] = useState<number>();
const [queryParamsState, setQueryParamsState] = useState({});
const [effectTipsModalOpenState, setEffectTipsModalOpenState] = useState<boolean>(false);
@@ -74,21 +69,18 @@ const ModelCreateForm: React.FC<CreateFormProps> = ({
const [tagObjectIdState, setTagObjectIdState] = useState(modelItem?.tagObjectId);
const formValRef = useRef(initFormVal as any);
const [form] = Form.useForm();
const { databaseConfigList, selectModelId: modelId, selectDomainId, domainData } = domainManger;
const domainModel = useModel('SemanticModel.domainData');
const modelModel = useModel('SemanticModel.modelData');
const { selectDomainId, selectDomain: domainData } = domainModel;
const { selectModelId: modelId } = modelModel;
const databaseModel = useModel('SemanticModel.databaseData');
const { databaseConfigList } = databaseModel;
const updateFormVal = (val: any) => {
formValRef.current = val;
};
const [sqlFilter, setSqlFilter] = useState<string>('');
// useEffect(() => {
// const hasEmpty = fields.some((item) => {
// const { name, isCreateDimension, isCreateMetric } = item;
// if ((isCreateMetric || isCreateDimension) && !name) {
// return true;
// }
// return false;
// });
// setHasEmptyNameField(hasEmpty);
// }, [fields]);
const [fieldColumns, setFieldColumns] = useState<IDataSource.IExecuteSqlColumn[]>(
scriptColumns || [],
@@ -155,8 +147,8 @@ const ModelCreateForm: React.FC<CreateFormProps> = ({
const saveModel = async (queryParams: any) => {
setSaveLoading(true);
const queryDatasource = isEdit ? updateModel : createModel;
const { code, msg, data } = await queryDatasource(queryParams);
const querySaveModel = isEdit ? updateModel : createModel;
const { code, msg, data } = await querySaveModel(queryParams);
setSaveLoading(false);
if (code === 200) {
message.success('保存模型成功!');
@@ -218,7 +210,6 @@ const ModelCreateForm: React.FC<CreateFormProps> = ({
isCreateDimension,
name,
type,
// entityNames,
tagObjectId: modelItem?.tagObjectId,
});
break;
@@ -502,7 +493,6 @@ const ModelCreateForm: React.FC<CreateFormProps> = ({
onClick={() => {
handleNext(true);
}}
// disabled={hasEmptyNameField}
>
</Button>
@@ -590,6 +580,4 @@ const ModelCreateForm: React.FC<CreateFormProps> = ({
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(ModelCreateForm);
export default ModelCreateForm;

View File

@@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
import { Button, Table, message, Tooltip, Space, Dropdown } from 'antd';
import SplitPane from 'react-split-pane';
import Pane from 'react-split-pane/lib/Pane';
import { connect } from 'umi';
import { useModel } from '@umijs/max';
import sqlFormatter from 'sql-formatter';
import {
FullscreenOutlined,
@@ -19,7 +19,6 @@ import FullScreen from '@/components/FullScreen';
import SqlEditor from '@/components/SqlEditor';
import type { TaskResultItem, TaskResultColumn } from '../data';
import { excuteSql } from '@/pages/SemanticModel/service';
import type { Dispatch } from 'umi';
import type { StateType } from '../../model';
import SqlParams from './SqlParams';
import styles from '../style.less';
@@ -37,8 +36,6 @@ export type DataSourceSubmitData = {
};
type IProps = {
domainManger: StateType;
dispatch: Dispatch;
dataSourceItem: IDataSource.IDataSourceItem;
onUpdateSql?: (sql: string) => void;
sql?: string;
@@ -61,13 +58,14 @@ type DatabaseItem = {
};
const SqlDetail: React.FC<IProps> = ({
domainManger,
dataSourceItem,
onSubmitSuccess,
sql = '',
onUpdateSql,
}) => {
const { databaseConfigList } = domainManger;
const databaseModel = useModel('SemanticModel.databaseData');
const { databaseConfigList } = databaseModel;
const [resultTable, setResultTable] = useState<ResultTableItem[]>([]);
const [resultTableLoading, setResultTableLoading] = useState(false);
const [resultCols, setResultCols] = useState<ResultColItem[]>([]);
@@ -385,7 +383,6 @@ const SqlDetail: React.FC<IProps> = ({
}, [resultTable, isSqlResFullScreen]);
useEffect(() => {
// queryDatabaseConfig();
const windowHeight = window.innerHeight;
let size: ScreenSize = 'small';
if (windowHeight > 1100) {
@@ -479,10 +476,7 @@ const SqlDetail: React.FC<IProps> = ({
onSelect={onSelect}
/>
</div>
<div
className={variableCollapsed ? styles.hideSqlParams : styles.sqlParams}
// style={{ height: sqlEditorHeight }}
>
<div className={variableCollapsed ? styles.hideSqlParams : styles.sqlParams}>
<SqlParams
value={sqlParams}
onChange={(params) => {
@@ -538,6 +532,4 @@ const SqlDetail: React.FC<IProps> = ({
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(SqlDetail);
export default SqlDetail;

View File

@@ -1,13 +1,7 @@
import React from 'react';
import { connect } from 'umi';
import type { StateType } from './model';
import OverviewContainer from './OverviewContainer';
import type { Dispatch } from 'umi';
type Props = {
domainManger: StateType;
dispatch: Dispatch;
};
type Props = {};
const DomainManager: React.FC<Props> = () => {
return (
<>
@@ -16,6 +10,4 @@ const DomainManager: React.FC<Props> = () => {
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(DomainManager);
export default DomainManager;

View File

@@ -30,17 +30,14 @@ import './index.less';
/** Mock所有与服务端交互的接口 */
import { MockApi } from './service';
type Props = {
domainManger: StateType;
dispatch: Dispatch;
};
type Props = {};
/** 鼠标的引用 */
let cursorTipRef: HTMLDivElement;
/** 鼠标在画布的位置 */
let cursorLocation: any;
const DomainManger: React.FC<Props> = (demoProps: Props) => {
const HeadLessFlows: React.FC<Props> = (demoProps: Props) => {
/** XFlow应用实例 */
const app = useXFlowApp();
@@ -309,6 +306,4 @@ const DomainManger: React.FC<Props> = (demoProps: Props) => {
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(DomainManger);
export default HeadLessFlows;

View File

@@ -1,8 +1,7 @@
import { message, Tabs, Button, Space } from 'antd';
import React, { useState, useEffect } from 'react';
import { getTagData } from '../service';
import { connect, useParams, history } from 'umi';
import type { StateType } from '../model';
import { useParams, history } from 'umi';
import styles from './style.less';
import { ArrowLeftOutlined } from '@ant-design/icons';
import TagTrendSection from './components/TagTrendSection';
@@ -16,7 +15,7 @@ type Props = Record<string, any>;
const TagDetail: React.FC<Props> = () => {
const params: any = useParams();
const tagId = params.tagId;
const [tagData, setTagData] = useState<ISemantic.IMetricItem>();
const [tagData, setTagData] = useState<ISemantic.ITagItem>();
const [dimensionMap, setDimensionMap] = useState<Record<string, ISemantic.IDimensionItem>>({});
const [metricMap, setMetricMap] = useState<Record<string, ISemantic.IMetricItem>>({});
@@ -146,6 +145,4 @@ const TagDetail: React.FC<Props> = () => {
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(TagDetail);
export default TagDetail;

View File

@@ -2,9 +2,7 @@ import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { message, Space, Popconfirm } from 'antd';
import React, { useRef, useState, useEffect } from 'react';
import type { Dispatch } from 'umi';
import { connect, useModel } from 'umi';
import type { StateType } from '../model';
import { useModel } from 'umi';
import { SENSITIVE_LEVEL_ENUM } from '../constant';
import { getTagList, deleteTag, batchDeleteTag, getTagObjectList } from '../service';
import TagFilter from './components/TagFilter';
@@ -15,10 +13,7 @@ import { ISemantic } from '../data';
import BatchCtrlDropDownButton from '@/components/BatchCtrlDropDownButton';
import { ColumnsConfig } from '../components/TableColumnRender';
type Props = {
dispatch: Dispatch;
domainManger: StateType;
};
type Props = {};
type QueryMetricListParams = {
id?: string;
@@ -29,11 +24,9 @@ type QueryMetricListParams = {
[key: string]: any;
};
const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
const ClassMetricTable: React.FC<Props> = ({}) => {
const { initialState = {} } = useModel('@@initialState');
const { currentUser = {} } = initialState as any;
const { selectDomainId, selectModelId: modelId } = domainManger;
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const defaultPagination = {
current: 1,
@@ -400,8 +393,6 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
{createModalVisible && (
<TagInfoCreateForm
domainId={selectDomainId}
modelId={Number(modelId)}
createModalVisible={createModalVisible}
tagItem={tagItem}
onSubmit={() => {
@@ -416,6 +407,4 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
</>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(ClassMetricTable);
export default ClassMetricTable;

View File

@@ -2,10 +2,8 @@ import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { message, Button, Space, Popconfirm, Input, Select } from 'antd';
import React, { useRef, useState, useEffect } from 'react';
import type { Dispatch } from 'umi';
import { StatusEnum } from '../../enum';
import { connect } from 'umi';
import type { StateType } from '../../model';
import { useModel } from '@umijs/max';
import { SENSITIVE_LEVEL_ENUM, SENSITIVE_LEVEL_OPTIONS } from '../../constant';
import { getTagList, deleteTag, batchUpdateTagStatus } from '../../service';
import TagInfoCreateForm from './TagInfoCreateForm';
@@ -17,13 +15,14 @@ import { ISemantic } from '../../data';
import { ColumnsConfig } from '../../components/TableColumnRender';
import TagValueSettingModal from './TagValueSettingModal';
type Props = {
dispatch: Dispatch;
domainManger: StateType;
};
type Props = {};
const ClassTagTable: React.FC<Props> = ({}) => {
const domainModel = useModel('SemanticModel.domainData');
const modelModel = useModel('SemanticModel.modelData');
const { selectDomainId } = domainModel;
const { selectModelId: modelId } = modelModel;
const ClassTagTable: React.FC<Props> = ({ domainManger, dispatch }) => {
const { selectModelId: modelId, selectDomainId } = domainManger;
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const [tagItem, setTagItem] = useState<ISemantic.ITagItem>();
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
@@ -369,6 +368,4 @@ const ClassTagTable: React.FC<Props> = ({ domainManger, dispatch }) => {
</>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(ClassTagTable);
export default ClassTagTable;

View File

@@ -15,8 +15,7 @@ import { ISemantic } from '../../data';
export type CreateFormProps = {
datasourceId?: number;
domainId: number;
modelId: number;
modelId?: number;
createModalVisible: boolean;
tagItem?: ISemantic.ITagItem;
onCancel?: () => void;
@@ -78,8 +77,8 @@ const TagInfoCreateForm: React.FC<CreateFormProps> = ({
const forward = () => setCurrentStep(currentStep + 1);
const backward = () => setCurrentStep(currentStep - 1);
const queryModelDetail = async () => {
const { code, data } = await getModelDetail({ modelId: modelId || tagItem?.modelId });
const queryModelDetail = async (modelId) => {
const { code, data } = await getModelDetail({ modelId });
if (code === 200) {
if (Array.isArray(data?.modelDetail?.fields)) {
if (Array.isArray(tagItem?.tagDefineParams?.dependencies)) {
@@ -112,10 +111,14 @@ const TagInfoCreateForm: React.FC<CreateFormProps> = ({
};
useEffect(() => {
queryModelDetail();
queryDimensionList(modelId);
queryMetricList(modelId);
}, [modelId]);
const id = modelId || tagItem?.modelId;
if (!id) {
return;
}
queryModelDetail(id);
queryDimensionList(id);
queryMetricList(id);
}, [modelId, tagItem]);
const handleNext = async () => {
const fieldsValue = await form.validateFields();
@@ -226,7 +229,7 @@ const TagInfoCreateForm: React.FC<CreateFormProps> = ({
if (isArrayOfValues(tagItem?.tagDefineParams?.dependencies)) {
const fieldList = list.map((item: ISemantic.IDimensionItem) => {
const { id } = item;
if (tagItem.tagDefineParams.dependencies.includes(id)) {
if (tagItem?.tagDefineParams.dependencies.includes(id)) {
return {
...item,
orderNumber: 9999,
@@ -262,7 +265,7 @@ const TagInfoCreateForm: React.FC<CreateFormProps> = ({
if (isArrayOfValues(tagItem?.tagDefineParams?.dependencies)) {
const fieldList = list.map((item: ISemantic.IMetricItem) => {
const { id } = item;
if (tagItem.tagDefineParams.dependencies.includes(id)) {
if (tagItem?.tagDefineParams.dependencies.includes(id)) {
return {
...item,
orderNumber: 9999,

View File

@@ -1,6 +1,5 @@
import { Tag, Space, Tooltip, Typography } from 'antd';
import { Tag, Space, Tooltip } from 'antd';
import React, { ReactNode } from 'react';
import { connect } from 'umi';
import type { StateType } from '../../model';
import dayjs from 'dayjs';
import {
@@ -23,7 +22,6 @@ import IndicatorStar from '../../components/IndicatorStar';
type Props = {
tagData: ISemantic.ITagItem;
domainManger: StateType;
onNodeChange: (params?: { eventName?: string }) => void;
onEditBtnClick?: (tagData: any) => void;
onDimensionRelationBtnClick?: () => void;
@@ -251,6 +249,4 @@ const TagInfoSider: React.FC<Props> = ({ tagData, dimensionMap, metricMap }) =>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(TagInfoSider);
export default TagInfoSider;

View File

@@ -1,30 +1,24 @@
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { message, Button, Space, Popconfirm, Input, Select } from 'antd';
import { message, Button, Space, Popconfirm } from 'antd';
import React, { useRef, useState, useEffect } from 'react';
import type { Dispatch } from 'umi';
import { StatusEnum } from '../../enum';
import { connect } from 'umi';
import type { StateType } from '../../model';
import { SENSITIVE_LEVEL_ENUM, SENSITIVE_LEVEL_OPTIONS } from '../../constant';
import { useModel } from '@umijs/max';
import { getTagObjectList, deleteTagObject, batchUpdateTagStatus } from '../../service';
import TagObjectCreateForm from './TagObjectCreateForm';
// import BatchCtrlDropDownButton from '@/components/BatchCtrlDropDownButton';
import TableHeaderFilter from '../../components/TableHeaderFilter';
import moment from 'moment';
import styles from '../style.less';
import { ISemantic } from '../../data';
import { ColumnsConfig } from '../../components/TableColumnRender';
import TagValueSettingModal from './TagValueSettingModal';
type Props = {
dispatch: Dispatch;
domainManger: StateType;
};
type Props = {};
const TagObjectTable: React.FC<Props> = ({ domainManger, dispatch }) => {
const { selectModelId: modelId, selectDomainId } = domainManger;
const TagObjectTable: React.FC<Props> = ({}) => {
const domainModel = useModel('SemanticModel.domainData');
const modelModel = useModel('SemanticModel.modelData');
const { selectDomainId } = domainModel;
const { selectModelId: modelId } = modelModel;
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const [tagItem, setTagItem] = useState<ISemantic.ITagItem>();
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
@@ -273,6 +267,4 @@ const TagObjectTable: React.FC<Props> = ({ domainManger, dispatch }) => {
</>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(TagObjectTable);
export default TagObjectTable;

View File

@@ -1,28 +1,19 @@
import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';
import { Button, Modal, Space } from 'antd';
import { KnowledgeConfigTypeEnum } from '../../enum';
import { ISemantic } from '../../data';
import DimensionValueSettingForm from '../../components/Entity/DimensionValueSettingForm';
import { connect } from 'umi';
import type { StateType } from '../../model';
export type CreateFormProps = {
onCancel: () => void;
tagItem: ISemantic.ITagItem;
open: boolean;
onSubmit: (values?: any) => void;
domainManger: StateType;
};
type TableDataSource = { techName: string; bizName: string; alias?: string[] };
const TagValueSettingModal: React.FC<CreateFormProps> = ({
onCancel,
open,
tagItem,
domainManger,
onSubmit,
}) => {
const TagValueSettingModal: React.FC<CreateFormProps> = ({ onCancel, open, tagItem, onSubmit }) => {
const [tableDataSource, setTableDataSource] = useState<TableDataSource[]>([]);
// const handleSubmit = async () => {
@@ -81,6 +72,4 @@ const TagValueSettingModal: React.FC<CreateFormProps> = ({
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(TagValueSettingModal);
export default TagValueSettingModal;

View File

@@ -1,7 +1,12 @@
import React from 'react';
import { Outlet } from '@umijs/max';
const market: React.FC = ({ children }) => {
return <>{children}</>;
const market: React.FC = () => {
return (
<>
<Outlet />
</>
);
};
export default market;

View File

@@ -112,6 +112,7 @@
padding: 0px;
background-color: transparent;
.tabContainer {
height: 100%;
width: calc(100vw - 450px);
background-color: rgb(240, 242, 245);
}

View File

@@ -1,8 +1,7 @@
import { message, Tabs, Button, Space } from 'antd';
import React, { useState, useEffect } from 'react';
import { getMetricData, getDimensionList, getDrillDownDimension } from '../service';
import { connect, useParams, history } from 'umi';
import type { StateType } from '../model';
import { useParams, history } from '@umijs/max';
import styles from './style.less';
import { ArrowLeftOutlined } from '@ant-design/icons';
import MetricTrendSection from '@/pages/SemanticModel/Metric/components/MetricTrendSection';
@@ -159,6 +158,4 @@ const MetricDetail: React.FC<Props> = () => {
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(MetricDetail);
export default MetricDetail;

View File

@@ -0,0 +1,127 @@
import { message, Tabs, Button, Space } from 'antd';
import React, { useState, useEffect } from 'react';
import { getMetricData, getDimensionList, getDrillDownDimension } from '../service';
import { connect, useParams, history } from 'umi';
import type { StateType } from '../model';
import styles from './style.less';
import { ArrowLeftOutlined } from '@ant-design/icons';
import MetricTrendSection from '@/pages/SemanticModel/Metric/components/MetricTrendSection';
import { ISemantic } from '../data';
import MetricBasicInfo from './components/MetricBasicInfo';
import DimensionAndMetricRelationModal from '../components/DimensionAndMetricRelationModal';
import MetricInfoEditSider from './MetricInfoEditSider';
import MetricInfoCreateForm from './components/MetricInfoCreateForm';
import { MetricSettingKey, MetricSettingWording } from './constants';
type Props = Record<string, any>;
const MetricDetail: React.FC<Props> = () => {
const params: any = useParams();
const metricId = params.metricId;
const [metricRelationModalOpenState, setMetricRelationModalOpenState] = useState<boolean>(false);
const [metircData, setMetircData] = useState<ISemantic.IMetricItem>();
const [dimensionList, setDimensionList] = useState<ISemantic.IDimensionItem[]>([]);
const [drillDownDimension, setDrillDownDimension] = useState<ISemantic.IDrillDownDimensionItem[]>(
[],
);
const [relationDimensionOptions, setRelationDimensionOptions] = useState<
{ value: string; label: string; modelId: number }[]
>([]);
const [settingKey, setSettingKey] = useState<MetricSettingKey>(MetricSettingKey.BASIC);
useEffect(() => {
if (!metricId) {
return;
}
queryMetricData(metricId);
queryDrillDownDimension(metricId);
}, [metricId]);
const queryMetricData = async (metricId: string) => {
const { code, data, msg } = await getMetricData(metricId);
if (code === 200) {
setMetircData({ ...data });
return;
}
message.error(msg);
};
const queryDrillDownDimension = async (metricId: number) => {
const { code, data, msg } = await getDrillDownDimension(metricId);
if (code === 200 && Array.isArray(data)) {
setDrillDownDimension(data);
const ids = data.map((item) => item.dimensionId);
queryDimensionList(ids);
return data;
} else {
setDimensionList([]);
setRelationDimensionOptions([]);
}
if (code !== 200) {
message.error(msg);
}
return [];
};
const queryDimensionList = async (ids: number[]) => {
if (!(Array.isArray(ids) && ids.length > 0)) {
setRelationDimensionOptions([]);
return;
}
const { code, data, msg } = await getDimensionList({ ids });
if (code === 200 && Array.isArray(data?.list)) {
setDimensionList(data.list);
setRelationDimensionOptions(
data.list.map((item: ISemantic.IMetricItem) => {
return { label: item.name, value: item.bizName, modelId: item.modelId };
}),
);
return data.list;
}
message.error(msg);
return [];
};
return (
<>
<div className={styles.metricEditWrapper}>
<div className={styles.metricDetail}>
<div className={styles.siderContainer}>
<MetricInfoEditSider
onSettingKeyChange={(key: string) => {
setSettingKey(key);
}}
metircData={metircData}
/>
</div>
<div className={styles.tabContainer}>
{/* {metircData && ( */}
<MetricInfoCreateForm
settingKey={settingKey}
// domainId={metircData?.domainId}
// modelId={metircData?.modelId}
metricItem={metircData}
/>
{/* )} */}
</div>
</div>
<DimensionAndMetricRelationModal
metricItem={metircData}
relationsInitialValue={drillDownDimension}
open={metricRelationModalOpenState}
onCancel={() => {
setMetricRelationModalOpenState(false);
}}
onSubmit={(relations) => {
queryMetricData(metricId);
queryDrillDownDimension(metricId);
setMetricRelationModalOpenState(false);
}}
/>
</div>
</>
);
};
export default MetricDetail;

View File

@@ -1,11 +1,9 @@
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { message, Space, Popconfirm, Tag, Spin, Tooltip } from 'antd';
import { message, Space, Popconfirm, Spin } from 'antd';
import MetricAddClass from './components/MetricAddClass';
import React, { useRef, useState, useEffect } from 'react';
import type { Dispatch } from 'umi';
import { connect, history, useModel } from 'umi';
import type { StateType } from '../model';
import { history, useModel } from '@umijs/max';
import { SENSITIVE_LEVEL_ENUM } from '../constant';
import {
queryMetric,
@@ -18,8 +16,7 @@ import {
import MetricFilter from './components/MetricFilter';
import MetricInfoCreateForm from '../components/MetricInfoCreateForm';
import MetricCardList from './components/MetricCardList';
import NodeInfoDrawer from '../SemanticGraph/components/NodeInfoDrawer';
import { SemanticNodeType, StatusEnum } from '../enum';
import { StatusEnum } from '../enum';
import moment from 'moment';
import styles from './style.less';
import { ISemantic } from '../data';
@@ -27,8 +24,7 @@ import BatchCtrlDropDownButton from '@/components/BatchCtrlDropDownButton';
import { ColumnsConfig } from '../components/TableColumnRender';
type Props = {
dispatch: Dispatch;
domainManger: StateType;
};
type QueryMetricListParams = {
@@ -40,11 +36,9 @@ type QueryMetricListParams = {
[key: string]: any;
};
const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
const ClassMetricTable: React.FC<Props> = ({ }) => {
const { initialState = {} } = useModel('@@initialState');
const { currentUser = {} } = initialState as any;
const { selectDomainId, selectModelId: modelId } = domainManger;
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const defaultPagination = {
current: 1,
@@ -59,7 +53,6 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
const [filterParams, setFilterParams] = useState<Record<string, any>>({
showType: localStorage.getItem('metricMarketShowType') === '1' ? true : false,
});
const [infoDrawerVisible, setInfoDrawerVisible] = useState<boolean>(false);
const [downloadLoading, setDownloadLoading] = useState<boolean>(false);
@@ -193,55 +186,16 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
{
dataIndex: 'name',
title: '指标',
// width: '20%',
width: 280,
fixed: 'left',
render: columnsConfig.indicatorInfo.render,
},
// {
// dataIndex: 'modelName',
// title: '所属模型',
// render: (_, record: any) => {
// if (record.hasAdminRes) {
// return (
// <a
// target="blank"
// href={`/webapp/model/${record.domainId}/${record.modelId}/metric`}
// // onClick={() => {
// // history.push(`/model/${record.domainId}/${record.modelId}/metric`);
// // }}
// >
// {record.modelName}
// </a>
// );
// }
// return <> {record.modelName}</>;
// },
// },
{
dataIndex: 'sensitiveLevel',
title: '敏感度',
// width: 150,
valueEnum: SENSITIVE_LEVEL_ENUM,
render: columnsConfig.sensitiveLevel.render,
},
// {
// dataIndex: 'isPublish',
// title: '是否发布',
// width: 100,
// search: false,
// render: (isPublish) => {
// switch (isPublish) {
// case 0:
// return '否';
// case 1:
// return <span style={{ color: '#1677ff' }}>是</span>;
// default:
// return <Tag color="default">未知</Tag>;
// }
// },
// },
{
dataIndex: 'description',
title: '描述',
@@ -259,7 +213,6 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
{
dataIndex: 'createdBy',
title: '创建人',
// width: 150,
search: false,
},
{
@@ -477,45 +430,18 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
{createModalVisible && (
<MetricInfoCreateForm
domainId={Number(selectDomainId)}
createModalVisible={createModalVisible}
modelId={modelId}
metricItem={metricItem}
onSubmit={() => {
setCreateModalVisible(false);
queryMetricList(filterParams);
dispatch({
type: 'domainManger/queryMetricList',
payload: {
domainId: selectDomainId,
},
});
}}
onCancel={() => {
setCreateModalVisible(false);
}}
/>
)}
{infoDrawerVisible && (
<NodeInfoDrawer
nodeData={{ ...metricItem, nodeType: SemanticNodeType.METRIC }}
placement="right"
onClose={() => {
setInfoDrawerVisible(false);
}}
width="100%"
open={infoDrawerVisible}
mask={true}
getContainer={false}
onEditBtnClick={(nodeData: any) => {
handleMetricEdit(nodeData);
}}
maskClosable={true}
onNodeChange={({ eventName }: { eventName: string }) => {
setInfoDrawerVisible(false);
}}
/>
)}
{addClassVisible && (
<MetricAddClass
ids={selectedRowKeys as number[]}
@@ -526,18 +452,10 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
onSuccess={() => {
setAddClassVisible(false);
queryMetricList(filterParams);
dispatch({
type: 'domainManger/queryMetricList',
payload: {
domainId: selectDomainId,
},
});
}}
/>
)}
</>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(ClassMetricTable);
export default ClassMetricTable

View File

@@ -0,0 +1,161 @@
import { Tag, Space, Tooltip } from 'antd';
import React, { useState } from 'react';
import dayjs from 'dayjs';
import { MetricSettingKey, MetricSettingWording } from './constants';
import {
ExportOutlined,
SolutionOutlined,
PartitionOutlined,
ProjectOutlined,
ConsoleSqlOutlined,
SettingOutlined,
} from '@ant-design/icons';
import styles from './style.less';
import { ISemantic } from '../data';
import IndicatorStar from '../components/IndicatorStar';
type Props = {
metircData: ISemantic.IMetricItem;
onSettingKeyChange?: (key: MetricSettingKey) => void;
};
const MetricInfoEditSider: React.FC<Props> = ({ metircData, onSettingKeyChange }) => {
const [settingKey, setSettingKey] = useState<MetricSettingKey>(MetricSettingKey.BASIC);
const settingList = [
{
icon: <ProjectOutlined />,
key: MetricSettingKey.BASIC,
text: MetricSettingWording[MetricSettingKey.BASIC],
},
{
icon: <ConsoleSqlOutlined />,
key: MetricSettingKey.SQL_CONFIG,
text: MetricSettingWording[MetricSettingKey.SQL_CONFIG],
},
// {
// icon: <DashboardOutlined />,
// key: MetricSettingKey.DIMENSION_CONFIG,
// text: MetricSettingWording[MetricSettingKey.DIMENSION_CONFIG],
// },
];
return (
<div className={styles.metricInfoSider}>
<div className={styles.sectionContainer}>
{metircData?.id ? (
<div className={styles.title}>
<div className={styles.name}>
<Space>
<IndicatorStar indicatorId={metircData?.id} initState={metircData?.isCollect} />
{metircData?.name}
{metircData?.hasAdminRes && (
<span
className={styles.gotoMetricListIcon}
onClick={() => {
window.open(`/webapp/model/${metircData.domainId}/${metircData.modelId}/`);
}}
>
<Tooltip title="前往所属模型指标列表">
<ExportOutlined />
</Tooltip>
</span>
)}
</Space>
</div>
{metircData?.bizName && <div className={styles.bizName}>{metircData.bizName}</div>}
</div>
) : (
<div className={styles.createTitle}>
<Space>
<SettingOutlined />
</Space>
</div>
)}
<hr className={styles.hr} />
<div className={styles.section} style={{ padding: '16px 0' }}>
<ul className={styles.settingList}>
{settingList.map((item) => {
return (
<li
className={item.key === settingKey ? styles.active : ''}
key={item.key}
onClick={() => {
onSettingKeyChange?.(item.key);
setSettingKey(item.key);
}}
>
<div className={styles.icon}>{item.icon}</div>
<div className={styles.content}>
<span className={styles.text}> {item.text}</span>
</div>
</li>
);
})}
</ul>
</div>
{/* <hr className={styles.hr} /> */}
{metircData?.id && (
<div className={styles.section} style={{ marginTop: 'auto' }}>
<div className={styles.sectionTitleBox}>
<span className={styles.sectionTitle}>
<Space>
<SolutionOutlined />
</Space>
</span>
</div>
<div className={styles.item}>
<span className={styles.itemLable}>: </span>
<span className={styles.itemValue}>
<Space>
<Tag icon={<PartitionOutlined />} color="#3b5999">
{metircData?.modelName || '模型名为空'}
</Tag>
{metircData?.hasAdminRes && (
<span
className={styles.gotoMetricListIcon}
onClick={() => {
window.open(`/webapp/model/${metircData.domainId}/0/overview`);
}}
>
<Tooltip title="前往模型设置页">
<ExportOutlined />
</Tooltip>
</span>
)}
</Space>
</span>
</div>
<div className={styles.item}>
<span className={styles.itemLable}>: </span>
<span className={styles.itemValue}>{metircData?.createdBy}</span>
</div>
<div className={styles.item}>
<span className={styles.itemLable}>: </span>
<span className={styles.itemValue}>
{metircData?.createdAt
? dayjs(metircData?.createdAt).format('YYYY-MM-DD HH:mm:ss')
: ''}
</span>
</div>
<div className={styles.item}>
<span className={styles.itemLable}>: </span>
<span className={styles.itemValue}>
{metircData?.createdAt
? dayjs(metircData?.updatedAt).format('YYYY-MM-DD HH:mm:ss')
: ''}
</span>
</div>
</div>
)}
{/* <hr className={styles.hr} /> */}
</div>
</div>
);
};
export default MetricInfoEditSider;

View File

@@ -1,7 +1,5 @@
import { Tag, Space, Tooltip, Typography } from 'antd';
import React from 'react';
import { connect } from 'umi';
import type { StateType } from '../model';
import { isArrayOfValues } from '@/utils/utils';
import dayjs from 'dayjs';
import {
@@ -22,7 +20,6 @@ const { Text } = Typography;
type Props = {
metircData: ISemantic.IMetricItem;
domainManger: StateType;
relationDimensionOptions: { value: string; label: string; modelId: number }[];
onNodeChange: (params?: { eventName?: string }) => void;
onEditBtnClick?: (metircData: any) => void;
@@ -256,6 +253,4 @@ const MetricInfoSider: React.FC<Props> = ({
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(MetricInfoSider);
export default MetricInfoSider;

View File

@@ -3,10 +3,7 @@ import React, { useState } from 'react';
import { Dropdown, Popconfirm, Typography } from 'antd';
import { EllipsisOutlined } from '@ant-design/icons';
import { ISemantic } from '../../data';
import { connect } from 'umi';
import icon from '../../../../assets/icon/sourceState.svg';
import type { Dispatch } from 'umi';
import type { StateType } from '../../model';
import { SemanticNodeType } from '../../enum';
import styles from '../style.less';
@@ -17,8 +14,6 @@ type Props = {
onMetricChange?: (metricItem: ISemantic.IMetricItem) => void;
onEditBtnClick?: (metricItem: ISemantic.IMetricItem) => void;
onDeleteBtnClick?: (metricItem: ISemantic.IMetricItem) => void;
domainManger: StateType;
dispatch: Dispatch;
};
const MetricCardList: React.FC<Props> = ({
@@ -27,7 +22,6 @@ const MetricCardList: React.FC<Props> = ({
onMetricChange,
onEditBtnClick,
onDeleteBtnClick,
domainManger,
}) => {
const [currentNodeData, setCurrentNodeData] = useState<any>({});
@@ -129,6 +123,4 @@ const MetricCardList: React.FC<Props> = ({
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(MetricCardList);
export default MetricCardList;

View File

@@ -0,0 +1,944 @@
import React, { useEffect, useRef, useState } from 'react';
import {
Form,
Button,
Input,
Select,
Radio,
Switch,
InputNumber,
message,
Result,
Row,
Col,
Space,
Divider,
Tooltip,
Tag,
} from 'antd';
import MetricMeasuresFormTable from '../../components/MetricMeasuresFormTable';
import { SENSITIVE_LEVEL_OPTIONS, METRIC_DEFINE_TYPE, TAG_DEFINE_TYPE } from '../../constant';
import { formLayout } from '@/components/FormHelper/utils';
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
import styles from '../../components/style.less';
import {
getMetricsToCreateNewMetric,
getModelDetail,
getDrillDownDimension,
batchCreateTag,
batchDeleteTag,
} from '../../service';
import { ArrowLeftOutlined } from '@ant-design/icons';
import MetricMetricFormTable from '../../components/MetricMetricFormTable';
import MetricFieldFormTable from '../../components/MetricFieldFormTable';
import DimensionAndMetricRelationModal from '../../components/DimensionAndMetricRelationModal';
import TableTitleTooltips from '../../components/TableTitleTooltips';
import { createMetric, updateMetric, mockMetricAlias, getMetricTags } from '../../service';
import { MetricSettingKey, MetricSettingWording } from '../constants';
import { ISemantic } from '../../data';
import { history } from '@umijs/max';
export type CreateFormProps = {
datasourceId?: number;
metricItem: any;
settingKey: MetricSettingKey;
onCancel?: () => void;
onSubmit?: (values: any) => void;
};
const FormItem = Form.Item;
const { TextArea } = Input;
const { Option } = Select;
const queryParamsTypeParamsKey = {
[METRIC_DEFINE_TYPE.MEASURE]: 'metricDefineByMeasureParams',
[METRIC_DEFINE_TYPE.METRIC]: 'metricDefineByMetricParams',
[METRIC_DEFINE_TYPE.FIELD]: 'metricDefineByFieldParams',
};
const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
datasourceId,
onCancel,
settingKey,
metricItem,
onSubmit,
}) => {
const isEdit = !!metricItem?.id;
const domainId = metricItem?.domainId;
const modelId = metricItem?.modelId;
const [currentStep, setCurrentStep] = useState(0);
const formValRef = useRef({} as any);
const [form] = Form.useForm();
const updateFormVal = (val: any) => {
const formVal = {
...formValRef.current,
...val,
};
formValRef.current = formVal;
};
const [classMeasureList, setClassMeasureList] = useState<ISemantic.IMeasure[]>([]);
const [exprTypeParamsState, setExprTypeParamsState] = useState<{
[METRIC_DEFINE_TYPE.MEASURE]: ISemantic.IMeasureTypeParams;
[METRIC_DEFINE_TYPE.METRIC]: ISemantic.IMetricTypeParams;
[METRIC_DEFINE_TYPE.FIELD]: ISemantic.IFieldTypeParams;
}>({
[METRIC_DEFINE_TYPE.MEASURE]: {
measures: [],
expr: '',
},
[METRIC_DEFINE_TYPE.METRIC]: {
metrics: [],
expr: '',
},
[METRIC_DEFINE_TYPE.FIELD]: {
fields: [],
expr: '',
},
} as any);
// const [exprTypeParamsState, setExprTypeParamsState] = useState<ISemantic.IMeasure[]>([]);
const [defineType, setDefineType] = useState(METRIC_DEFINE_TYPE.MEASURE);
const [createNewMetricList, setCreateNewMetricList] = useState<ISemantic.IMetricItem[]>([]);
const [fieldList, setFieldList] = useState<ISemantic.IFieldTypeParamsItem[]>([]);
const [isPercentState, setIsPercentState] = useState<boolean>(false);
const [isDecimalState, setIsDecimalState] = useState<boolean>(false);
const [hasMeasuresState, setHasMeasuresState] = useState<boolean>(true);
const [llmLoading, setLlmLoading] = useState<boolean>(false);
const [tagOptions, setTagOptions] = useState<{ label: string; value: string }[]>([]);
const [metricRelationModalOpenState, setMetricRelationModalOpenState] = useState<boolean>(false);
const [drillDownDimensions, setDrillDownDimensions] = useState<
ISemantic.IDrillDownDimensionItem[]
>([]);
const [drillDownDimensionsConfig, setDrillDownDimensionsConfig] = useState<
ISemantic.IDrillDownDimensionItem[]
>([]);
const forward = () => setCurrentStep(currentStep + 1);
const backward = () => setCurrentStep(currentStep - 1);
const queryModelDetail = async () => {
const { code, data } = await getModelDetail({ modelId: modelId || metricItem?.modelId });
if (code === 200) {
if (Array.isArray(data?.modelDetail?.fields)) {
if (Array.isArray(metricItem?.metricDefineByFieldParams?.fields)) {
const fieldList = data.modelDetail.fields.map((item: ISemantic.IFieldTypeParamsItem) => {
const { fieldName } = item;
if (
metricItem?.metricDefineByFieldParams?.fields.find(
(measureParamsItem: ISemantic.IFieldTypeParamsItem) =>
measureParamsItem.fieldName === fieldName,
)
) {
return {
...item,
orderNumber: 9999,
};
}
return {
...item,
orderNumber: 0,
};
});
const sortList = fieldList.sort(
(
a: ISemantic.IFieldTypeParamsItem & { orderNumber: number },
b: ISemantic.IFieldTypeParamsItem & { orderNumber: number },
) => b.orderNumber - a.orderNumber,
);
setFieldList(sortList);
} else {
setFieldList(data.modelDetail.fields);
}
}
if (Array.isArray(data?.modelDetail?.measures)) {
if (Array.isArray(metricItem?.metricDefineByMeasureParams?.measures)) {
const measureList = data.modelDetail.measures.map((item: ISemantic.IMeasure) => {
const { bizName } = item;
if (
metricItem?.metricDefineByMeasureParams?.measures.find(
(measureParamsItem: ISemantic.IMeasure) => measureParamsItem.bizName === bizName,
)
) {
return {
...item,
orderNumber: 9999,
};
}
return {
...item,
orderNumber: 0,
};
});
const sortMeasureList = measureList.sort(
(
a: ISemantic.IMeasure & { orderNumber: number },
b: ISemantic.IMeasure & { orderNumber: number },
) => b.orderNumber - a.orderNumber,
);
setClassMeasureList(sortMeasureList);
} else {
setClassMeasureList(data.modelDetail.measures);
}
if (datasourceId) {
const hasMeasures = data.some(
(item: ISemantic.IMeasure) => item.datasourceId === datasourceId,
);
setHasMeasuresState(hasMeasures);
}
return;
}
}
setClassMeasureList([]);
};
const queryDrillDownDimension = async (metricId: number) => {
const { code, data, msg } = await getDrillDownDimension(metricId);
if (code === 200 && Array.isArray(data)) {
setDrillDownDimensionsConfig(data);
}
if (code !== 200) {
message.error(msg);
}
return [];
};
useEffect(() => {
queryModelDetail();
queryMetricsToCreateNewMetric();
queryMetricTags();
}, []);
const handleSave = async () => {
const fieldsValue = await form.validateFields();
const submitForm = {
...formValRef.current,
...fieldsValue,
metricDefineType: defineType,
[queryParamsTypeParamsKey[defineType]]: exprTypeParamsState[defineType],
};
updateFormVal(submitForm);
await saveMetric(submitForm);
};
const initData = () => {
const {
id,
name,
bizName,
description,
sensitiveLevel,
typeParams,
isTag,
dataFormat,
dataFormatType,
alias,
classifications,
metricDefineType,
metricDefineByMeasureParams,
metricDefineByMetricParams,
metricDefineByFieldParams,
} = metricItem;
const isPercent = dataFormatType === 'percent';
const isDecimal = dataFormatType === 'decimal';
const initValue = {
id,
name,
bizName,
sensitiveLevel,
description,
classifications,
isTag,
// isPercent,
dataFormatType: dataFormatType || '',
alias: alias && alias.trim() ? alias.split(',') : [],
dataFormat: dataFormat || {
decimalPlaces: 2,
needMultiply100: false,
},
};
const editInitFormVal = {
...formValRef.current,
...initValue,
};
if (metricDefineType === METRIC_DEFINE_TYPE.MEASURE) {
const { measures, expr } = metricDefineByMeasureParams || {};
setExprTypeParamsState({
...exprTypeParamsState,
[METRIC_DEFINE_TYPE.MEASURE]: {
measures: measures || [],
expr: expr || '',
},
});
}
if (metricDefineType === METRIC_DEFINE_TYPE.METRIC) {
const { metrics, expr } = metricDefineByMetricParams || {};
setExprTypeParamsState({
...exprTypeParamsState,
[METRIC_DEFINE_TYPE.METRIC]: {
metrics: metrics || [],
expr: expr || '',
},
});
}
if (metricDefineType === METRIC_DEFINE_TYPE.FIELD) {
const { fields, expr } = metricDefineByFieldParams || {};
setExprTypeParamsState({
...exprTypeParamsState,
[METRIC_DEFINE_TYPE.FIELD]: {
fields: fields || [],
expr: expr || '',
},
});
}
updateFormVal(editInitFormVal);
form.setFieldsValue(initValue);
setDefineType(metricDefineType);
setIsPercentState(isPercent);
setIsDecimalState(isDecimal);
queryDrillDownDimension(metricItem?.id);
};
useEffect(() => {
if (isEdit) {
initData();
}
}, [metricItem]);
const isEmptyConditions = (
metricDefineType: METRIC_DEFINE_TYPE,
metricDefineParams:
| ISemantic.IMeasureTypeParams
| ISemantic.IMetricTypeParams
| ISemantic.IFieldTypeParams,
) => {
if (metricDefineType === METRIC_DEFINE_TYPE.MEASURE) {
const { measures } = (metricDefineParams as ISemantic.IMeasureTypeParams) || {};
if (!(Array.isArray(measures) && measures.length > 0)) {
message.error('请添加一个度量');
return true;
}
}
if (metricDefineType === METRIC_DEFINE_TYPE.METRIC) {
const { metrics } = (metricDefineParams as ISemantic.IMetricTypeParams) || {};
if (!(Array.isArray(metrics) && metrics.length > 0)) {
message.error('请添加一个指标');
return true;
}
}
if (metricDefineType === METRIC_DEFINE_TYPE.FIELD) {
const { fields } = (metricDefineParams as ISemantic.IFieldTypeParams) || {};
if (!(Array.isArray(fields) && fields.length > 0)) {
message.error('请添加一个字段');
return true;
}
}
return false;
};
const saveMetric = async (fieldsValue: any) => {
const queryParams = {
modelId: isEdit ? metricItem.modelId : modelId,
relateDimension: {
...(metricItem?.relateDimension || {}),
drillDownDimensions,
},
...fieldsValue,
};
const { alias, dataFormatType } = queryParams;
queryParams.alias = Array.isArray(alias) ? alias.join(',') : '';
if (!queryParams[queryParamsTypeParamsKey[defineType]]?.expr) {
message.error('请输入度量表达式');
return;
}
if (!dataFormatType) {
delete queryParams.dataFormat;
}
if (isEmptyConditions(defineType, queryParams[queryParamsTypeParamsKey[defineType]])) {
return;
}
let saveMetricQuery = createMetric;
if (queryParams.id) {
saveMetricQuery = updateMetric;
}
const { code, msg, data } = await saveMetricQuery(queryParams);
if (code === 200) {
if (queryParams.isTag) {
queryBatchExportTag(data.id || metricItem?.id);
}
if (metricItem?.id && !queryParams.isTag) {
queryBatchDelete(metricItem);
}
message.success('编辑指标成功');
onSubmit?.(queryParams);
return;
}
message.error(msg);
};
const queryBatchDelete = async (metricItem: ISemantic.IMetricItem) => {
const { code, msg } = await batchDeleteTag([
{
itemIds: [metricItem.id],
tagDefineType: TAG_DEFINE_TYPE.METRIC,
},
]);
if (code === 200) {
return;
}
message.error(msg);
};
const queryBatchExportTag = async (id: number) => {
const { code, msg } = await batchCreateTag([
{ itemId: id, tagDefineType: TAG_DEFINE_TYPE.METRIC },
]);
if (code === 200) {
return;
}
message.error(msg);
};
const generatorMetricAlias = async () => {
setLlmLoading(true);
const { code, data } = await mockMetricAlias({ ...metricItem });
const formAlias = form.getFieldValue('alias');
setLlmLoading(false);
if (code === 200) {
form.setFieldValue('alias', Array.from(new Set([...formAlias, ...data])));
} else {
message.error('大语言模型解析异常');
}
};
const queryMetricTags = async () => {
const { code, data } = await getMetricTags();
if (code === 200) {
setTagOptions(
Array.isArray(data)
? data.map((tag: string) => {
return { label: tag, value: tag };
})
: [],
);
} else {
message.error('获取指标标签失败');
}
};
const queryMetricsToCreateNewMetric = async () => {
if (!metricItem?.id) {
return;
}
const { code, data } = await getMetricsToCreateNewMetric({
modelId: modelId || metricItem?.modelId,
});
if (code === 200) {
if (Array.isArray(metricItem?.metricDefineByMetricParams?.metrics)) {
const fieldList = data.map((item: ISemantic.IMetricTypeParamsItem) => {
const { bizName } = item;
if (
metricItem?.metricDefineByMetricParams?.metrics.find(
(measureParamsItem: ISemantic.IMetricTypeParamsItem) =>
measureParamsItem.bizName === bizName,
)
) {
return {
...item,
orderNumber: 9999,
};
}
return {
...item,
orderNumber: 0,
};
});
const sortList = fieldList.sort(
(
a: ISemantic.IMetricTypeParamsItem & { orderNumber: number },
b: ISemantic.IMetricTypeParamsItem & { orderNumber: number },
) => b.orderNumber - a.orderNumber,
);
setCreateNewMetricList(sortList);
} else {
setCreateNewMetricList(data);
}
} else {
message.error('获取指标标签失败');
}
};
const renderContent = () => {
if (settingKey === MetricSettingKey.SQL_CONFIG) {
return (
<div
style={{
marginLeft: '-24px',
}}
>
<div
style={{
padding: '0 0 0px 24px',
}}
>
<Space size={20}>
<Radio.Group
buttonStyle="solid"
value={defineType}
onChange={(e) => {
setDefineType(e.target.value);
}}
>
<Radio.Button value={METRIC_DEFINE_TYPE.MEASURE}></Radio.Button>
<Radio.Button value={METRIC_DEFINE_TYPE.METRIC}></Radio.Button>
<Radio.Button value={METRIC_DEFINE_TYPE.FIELD}></Radio.Button>
</Radio.Group>
{defineType === METRIC_DEFINE_TYPE.METRIC && (
<p className={styles.desc}>
<Tag color="#2499ef14" className={styles.markerTag}>
</Tag>
</p>
)}
</Space>
</div>
{defineType === METRIC_DEFINE_TYPE.MEASURE && (
<>
<MetricMeasuresFormTable
datasourceId={datasourceId}
typeParams={exprTypeParamsState[METRIC_DEFINE_TYPE.MEASURE]}
measuresList={classMeasureList}
onFieldChange={(measures: ISemantic.IMeasure[]) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.MEASURE]: {
...prevState[METRIC_DEFINE_TYPE.MEASURE],
measures,
},
};
});
}}
onSqlChange={(expr: string) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.MEASURE]: {
...prevState[METRIC_DEFINE_TYPE.MEASURE],
expr,
},
};
});
}}
/>
</>
)}
{defineType === METRIC_DEFINE_TYPE.METRIC && (
<>
<MetricMetricFormTable
typeParams={exprTypeParamsState[METRIC_DEFINE_TYPE.METRIC]}
metricList={createNewMetricList}
onFieldChange={(metrics: ISemantic.IMetricTypeParamsItem[]) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.METRIC]: {
...prevState[METRIC_DEFINE_TYPE.METRIC],
metrics,
},
};
});
}}
onSqlChange={(expr: string) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.METRIC]: {
...prevState[METRIC_DEFINE_TYPE.METRIC],
expr,
},
};
});
}}
/>
</>
)}
{defineType === METRIC_DEFINE_TYPE.FIELD && (
<>
<MetricFieldFormTable
typeParams={exprTypeParamsState[METRIC_DEFINE_TYPE.FIELD]}
fieldList={fieldList}
onFieldChange={(fields: ISemantic.IFieldTypeParamsItem[]) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.FIELD]: {
...prevState[METRIC_DEFINE_TYPE.FIELD],
fields,
},
};
});
}}
onSqlChange={(expr: string) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.FIELD]: {
...prevState[METRIC_DEFINE_TYPE.FIELD],
expr,
},
};
});
}}
/>
</>
)}
</div>
);
}
return (
<>
<FormItem hidden={true} name="id" label="ID">
<Input placeholder="id" />
</FormItem>
<Row gutter={20}>
<Col span={12}>
<FormItem
name="name"
label="指标名称"
rules={[{ required: true, message: '请输入指标名称' }]}
>
<Input placeholder="名称不可重复" />
</FormItem>
</Col>
<Col span={12}>
<FormItem
name="bizName"
label="英文名称"
rules={[{ required: true, message: '请输入英文名称' }]}
>
<Input placeholder="名称不可重复" disabled={isEdit} />
</FormItem>
</Col>
</Row>
<Row gutter={20}>
<Col span={12}>
<FormItem
name="sensitiveLevel"
label="敏感度"
rules={[{ required: true, message: '请选择敏感度' }]}
>
<Select placeholder="请选择敏感度">
{SENSITIVE_LEVEL_OPTIONS.map((item) => (
<Option key={item.value} value={item.value}>
{item.label}
</Option>
))}
</Select>
</FormItem>
</Col>
<Col span={12}>
<FormItem name="classifications" label="分类">
<Select
mode="tags"
placeholder="支持手动输入及选择"
tokenSeparators={[',']}
maxTagCount={9}
options={tagOptions}
/>
</FormItem>
</Col>
</Row>
<FormItem
name="description"
label={
<TableTitleTooltips
title="业务口径"
overlayInnerStyle={{ width: 600 }}
tooltips={
<>
<p>
使使
</p>
<p>1. </p>
<p>2. </p>
<p>3. 使使</p>
<p>4. </p>
<p>
便
</p>
</>
}
/>
}
rules={[{ required: true, message: '请输入业务口径' }]}
>
<TextArea placeholder="请输入业务口径" style={{ minHeight: 173 }} />
</FormItem>
<FormItem label="别名">
<Row gutter={20}>
<Col flex="1 1 200px">
<FormItem name="alias" noStyle>
<Select
style={{ maxWidth: 500 }}
mode="tags"
placeholder="输入别名后回车确认,多别名输入、复制粘贴支持英文逗号自动分隔"
tokenSeparators={[',']}
maxTagCount={9}
/>
</FormItem>
</Col>
{isEdit && (
<Col flex="0 1 75px">
<Tooltip title="智能填充将根据指标相关信息,使用大语言模型获取指标别名">
<Button
type="primary"
loading={llmLoading}
style={{ top: '5px' }}
onClick={() => {
generatorMetricAlias();
}}
>
</Button>
</Tooltip>
</Col>
)}
</Row>
</FormItem>
<Divider />
<FormItem
name="isTag"
valuePropName="checked"
getValueFromEvent={(value) => {
return value === true ? 1 : 0;
}}
getValueProps={(value) => {
return {
checked: value === 1,
};
}}
>
<Row gutter={20}>
<Col flex="1 1 200px">
<FormItemTitle
title={`设为标签`}
subTitle={`如果勾选,代表取值都是一种'标签',可用作对实体的圈选`}
/>
</Col>
<Col flex="0 1 75px">
<Switch />
</Col>
</Row>
</FormItem>
<Divider />
<FormItem>
<Row gutter={20}>
<Col flex="1 1 200px">
<FormItemTitle
title={'下钻维度配置'}
subTitle={'配置下钻维度后,将可以在指标卡中进行下钻'}
/>
</Col>
<Col flex="0 1 75px">
<Button
type="primary"
onClick={() => {
setMetricRelationModalOpenState(true);
}}
>
</Button>
</Col>
</Row>
</FormItem>
<Divider />
<FormItem label={<FormItemTitle title={'数据格式化'} />} name="dataFormatType">
<Radio.Group buttonStyle="solid" size="middle">
<Radio.Button value=""></Radio.Button>
<Radio.Button value="decimal"></Radio.Button>
<Radio.Button value="percent"></Radio.Button>
</Radio.Group>
</FormItem>
{(isPercentState || isDecimalState) && (
<FormItem
label={
<FormItemTitle
title={'小数位数'}
subTitle={`对小数位数进行设置如保留两位0.021252 -> 0.02${
isPercentState ? '%' : ''
}`}
/>
}
name={['dataFormat', 'decimalPlaces']}
>
<InputNumber placeholder="请输入需要保留小数位数" style={{ width: '300px' }} />
</FormItem>
)}
{isPercentState && (
<>
<FormItem
label={
<FormItemTitle
title={'原始值是否乘以100'}
subTitle={'如 原始值0.001 ->展示值0.1% '}
/>
}
name={['dataFormat', 'needMultiply100']}
valuePropName="checked"
>
<Switch />
</FormItem>
</>
)}
</>
);
};
const renderFooter = () => {
if (!hasMeasuresState) {
return <Button onClick={onCancel}></Button>;
}
if (currentStep === 1) {
return (
<>
<Button style={{ float: 'left' }} onClick={backward}>
</Button>
<Button onClick={onCancel}></Button>
<Button type="primary" onClick={handleSave}>
</Button>
</>
);
}
return (
<>
<Button onClick={onCancel}></Button>
<Button type="primary" onClick={handleSave}>
</Button>
</>
);
};
return (
<>
{hasMeasuresState ? (
<>
<div className={styles.infoCard}>
<div className={styles.infoCardTitle}>
<span style={{ flex: 'auto' }}>{MetricSettingWording[settingKey]}</span>
<span style={{ flex: 'none' }}>
<Button
size="middle"
type="link"
key="backListBtn"
onClick={() => {
history.back();
}}
>
<Space>
<ArrowLeftOutlined />
</Space>
</Button>
</span>
</div>
<div className={styles.infoCardContainer}>
<Form
className={styles.supersonicForm}
{...formLayout}
form={form}
initialValues={{
...formValRef.current,
dataFormatType: '',
}}
onValuesChange={(value, values: any) => {
const { dataFormatType } = values;
if (dataFormatType === 'percent') {
setIsPercentState(true);
setIsDecimalState(false);
}
if (dataFormatType === 'decimal') {
setIsPercentState(false);
setIsDecimalState(true);
}
if (!dataFormatType) {
setIsPercentState(false);
setIsDecimalState(false);
}
}}
>
{renderContent()}
</Form>
</div>
<div className={styles.infoCardFooter}>
<div className={styles.infoCardFooterContainer}>
<Button type="primary" onClick={handleSave}>
</Button>
</div>
</div>
</div>
<DimensionAndMetricRelationModal
metricItem={metricItem}
relationsInitialValue={drillDownDimensionsConfig}
open={metricRelationModalOpenState}
onCancel={() => {
setMetricRelationModalOpenState(false);
}}
onSubmit={(relations) => {
setDrillDownDimensions(relations);
setMetricRelationModalOpenState(false);
}}
onRefreshRelationData={() => {
queryDrillDownDimension(metricItem?.id);
}}
/>
</>
) : (
<Result
style={{ background: '#fff' }}
status="warning"
subTitle="当前数据源缺少度量,无法创建指标。请前往数据源配置中,将字段设置为度量"
extra={
<Button
type="primary"
key="console"
onClick={() => {
history.replace(`/model/${domainId}/${modelId || metricItem?.modelId}/dataSource`);
onCancel?.();
}}
>
</Button>
}
/>
)}
</>
);
};
export default MetricInfoCreateForm;

View File

@@ -0,0 +1,540 @@
import React, { useEffect, useRef, useState } from 'react';
import {
Form,
Button,
Input,
Select,
Radio,
Switch,
InputNumber,
message,
Result,
Row,
Col,
Space,
Divider,
Tooltip,
Tag,
} from 'antd';
import MetricMeasuresFormTable from '../../components/MetricMeasuresFormTable';
import { SENSITIVE_LEVEL_OPTIONS, METRIC_DEFINE_TYPE, TAG_DEFINE_TYPE } from '../../constant';
import { formLayout } from '@/components/FormHelper/utils';
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
import styles from '../../components/style.less';
import {
getMetricsToCreateNewMetric,
getModelDetail,
getDrillDownDimension,
batchCreateTag,
batchDeleteTag,
} from '../../service';
import MetricMetricFormTable from '../../components/MetricMetricFormTable';
import MetricFieldFormTable from '../../components/MetricFieldFormTable';
import DimensionAndMetricRelationModal from '../../components/DimensionAndMetricRelationModal';
import TableTitleTooltips from '../../components/TableTitleTooltips';
import { createMetric, updateMetric, mockMetricAlias, getMetricTags } from '../../service';
import { MetricSettingKey, MetricSettingWording } from '../constants';
import { ISemantic } from '../../data';
import { history } from 'umi';
export type CreateFormProps = {
datasourceId?: number;
domainId: number;
modelId: number;
metricItem: any;
settingKey: MetricSettingKey;
onCancel?: () => void;
onSubmit?: (values: any) => void;
};
const queryParamsTypeParamsKey = {
[METRIC_DEFINE_TYPE.MEASURE]: 'metricDefineByMeasureParams',
[METRIC_DEFINE_TYPE.METRIC]: 'metricDefineByMetricParams',
[METRIC_DEFINE_TYPE.FIELD]: 'metricDefineByFieldParams',
};
const MetricInfoCreateSqlConfig: React.FC<CreateFormProps> = ({
datasourceId,
modelId,
metricItem,
onSubmit,
}) => {
const isEdit = !!metricItem?.id;
const [currentStep, setCurrentStep] = useState(0);
const formValRef = useRef({} as any);
const [form] = Form.useForm();
const updateFormVal = (val: any) => {
const formVal = {
...formValRef.current,
...val,
};
formValRef.current = formVal;
};
const [classMeasureList, setClassMeasureList] = useState<ISemantic.IMeasure[]>([]);
const [exprTypeParamsState, setExprTypeParamsState] = useState<{
[METRIC_DEFINE_TYPE.MEASURE]: ISemantic.IMeasureTypeParams;
[METRIC_DEFINE_TYPE.METRIC]: ISemantic.IMetricTypeParams;
[METRIC_DEFINE_TYPE.FIELD]: ISemantic.IFieldTypeParams;
}>({
[METRIC_DEFINE_TYPE.MEASURE]: {
measures: [],
expr: '',
},
[METRIC_DEFINE_TYPE.METRIC]: {
metrics: [],
expr: '',
},
[METRIC_DEFINE_TYPE.FIELD]: {
fields: [],
expr: '',
},
} as any);
// const [exprTypeParamsState, setExprTypeParamsState] = useState<ISemantic.IMeasure[]>([]);
const [defineType, setDefineType] = useState(METRIC_DEFINE_TYPE.MEASURE);
const [createNewMetricList, setCreateNewMetricList] = useState<ISemantic.IMetricItem[]>([]);
const [fieldList, setFieldList] = useState<ISemantic.IFieldTypeParamsItem[]>([]);
const [drillDownDimensions, setDrillDownDimensions] = useState<
ISemantic.IDrillDownDimensionItem[]
>([]);
const [drillDownDimensionsConfig, setDrillDownDimensionsConfig] = useState<
ISemantic.IDrillDownDimensionItem[]
>([]);
const queryModelDetail = async () => {
const { code, data } = await getModelDetail({ modelId: modelId || metricItem?.modelId });
if (code === 200) {
if (Array.isArray(data?.modelDetail?.fields)) {
if (Array.isArray(metricItem?.metricDefineByFieldParams?.fields)) {
const fieldList = data.modelDetail.fields.map((item: ISemantic.IFieldTypeParamsItem) => {
const { fieldName } = item;
if (
metricItem?.metricDefineByFieldParams?.fields.find(
(measureParamsItem: ISemantic.IFieldTypeParamsItem) =>
measureParamsItem.fieldName === fieldName,
)
) {
return {
...item,
orderNumber: 9999,
};
}
return {
...item,
orderNumber: 0,
};
});
const sortList = fieldList.sort(
(
a: ISemantic.IFieldTypeParamsItem & { orderNumber: number },
b: ISemantic.IFieldTypeParamsItem & { orderNumber: number },
) => b.orderNumber - a.orderNumber,
);
setFieldList(sortList);
} else {
setFieldList(data.modelDetail.fields);
}
}
if (Array.isArray(data?.modelDetail?.measures)) {
if (Array.isArray(metricItem?.metricDefineByMeasureParams?.measures)) {
const measureList = data.modelDetail.measures.map((item: ISemantic.IMeasure) => {
const { bizName } = item;
if (
metricItem?.metricDefineByMeasureParams?.measures.find(
(measureParamsItem: ISemantic.IMeasure) => measureParamsItem.bizName === bizName,
)
) {
return {
...item,
orderNumber: 9999,
};
}
return {
...item,
orderNumber: 0,
};
});
const sortMeasureList = measureList.sort(
(
a: ISemantic.IMeasure & { orderNumber: number },
b: ISemantic.IMeasure & { orderNumber: number },
) => b.orderNumber - a.orderNumber,
);
setClassMeasureList(sortMeasureList);
} else {
setClassMeasureList(data.modelDetail.measures);
}
return;
}
}
setClassMeasureList([]);
};
const queryDrillDownDimension = async (metricId: number) => {
const { code, data, msg } = await getDrillDownDimension(metricId);
if (code === 200 && Array.isArray(data)) {
setDrillDownDimensionsConfig(data);
}
if (code !== 200) {
message.error(msg);
}
return [];
};
useEffect(() => {
queryModelDetail();
queryMetricsToCreateNewMetric();
}, []);
const initData = () => {
const {
id,
name,
bizName,
description,
sensitiveLevel,
typeParams,
isTag,
dataFormat,
dataFormatType,
alias,
classifications,
metricDefineType,
metricDefineByMeasureParams,
metricDefineByMetricParams,
metricDefineByFieldParams,
} = metricItem;
const initValue = {
id,
name,
bizName,
sensitiveLevel,
description,
classifications,
isTag,
// isPercent,
dataFormatType: dataFormatType || '',
alias: alias && alias.trim() ? alias.split(',') : [],
dataFormat: dataFormat || {
decimalPlaces: 2,
needMultiply100: false,
},
};
const editInitFormVal = {
...formValRef.current,
...initValue,
};
if (metricDefineType === METRIC_DEFINE_TYPE.MEASURE) {
const { measures, expr } = metricDefineByMeasureParams || {};
setExprTypeParamsState({
...exprTypeParamsState,
[METRIC_DEFINE_TYPE.MEASURE]: {
measures: measures || [],
expr: expr || '',
},
});
}
if (metricDefineType === METRIC_DEFINE_TYPE.METRIC) {
const { metrics, expr } = metricDefineByMetricParams || {};
setExprTypeParamsState({
...exprTypeParamsState,
[METRIC_DEFINE_TYPE.METRIC]: {
metrics: metrics || [],
expr: expr || '',
},
});
}
if (metricDefineType === METRIC_DEFINE_TYPE.FIELD) {
const { fields, expr } = metricDefineByFieldParams || {};
setExprTypeParamsState({
...exprTypeParamsState,
[METRIC_DEFINE_TYPE.FIELD]: {
fields: fields || [],
expr: expr || '',
},
});
}
updateFormVal(editInitFormVal);
form.setFieldsValue(initValue);
setDefineType(metricDefineType);
queryDrillDownDimension(metricItem?.id);
};
useEffect(() => {
if (isEdit) {
initData();
}
}, [metricItem]);
const isEmptyConditions = (
metricDefineType: METRIC_DEFINE_TYPE,
metricDefineParams:
| ISemantic.IMeasureTypeParams
| ISemantic.IMetricTypeParams
| ISemantic.IFieldTypeParams,
) => {
if (metricDefineType === METRIC_DEFINE_TYPE.MEASURE) {
const { measures } = (metricDefineParams as ISemantic.IMeasureTypeParams) || {};
if (!(Array.isArray(measures) && measures.length > 0)) {
message.error('请添加一个度量');
return true;
}
}
if (metricDefineType === METRIC_DEFINE_TYPE.METRIC) {
const { metrics } = (metricDefineParams as ISemantic.IMetricTypeParams) || {};
if (!(Array.isArray(metrics) && metrics.length > 0)) {
message.error('请添加一个指标');
return true;
}
}
if (metricDefineType === METRIC_DEFINE_TYPE.FIELD) {
const { fields } = (metricDefineParams as ISemantic.IFieldTypeParams) || {};
if (!(Array.isArray(fields) && fields.length > 0)) {
message.error('请添加一个字段');
return true;
}
}
return false;
};
const saveMetric = async (fieldsValue: any) => {
const queryParams = {
modelId: isEdit ? metricItem.modelId : modelId,
relateDimension: {
...(metricItem?.relateDimension || {}),
drillDownDimensions,
},
...fieldsValue,
};
const { alias, dataFormatType } = queryParams;
queryParams.alias = Array.isArray(alias) ? alias.join(',') : '';
if (!queryParams[queryParamsTypeParamsKey[defineType]]?.expr) {
message.error('请输入度量表达式');
return;
}
if (!dataFormatType) {
delete queryParams.dataFormat;
}
if (isEmptyConditions(defineType, queryParams[queryParamsTypeParamsKey[defineType]])) {
return;
}
let saveMetricQuery = createMetric;
if (queryParams.id) {
saveMetricQuery = updateMetric;
}
const { code, msg, data } = await saveMetricQuery(queryParams);
if (code === 200) {
if (queryParams.isTag) {
queryBatchExportTag(data.id || metricItem?.id);
}
if (metricItem?.id && !queryParams.isTag) {
queryBatchDelete(metricItem);
}
message.success('编辑指标成功');
onSubmit?.(queryParams);
return;
}
message.error(msg);
};
const queryBatchDelete = async (metricItem: ISemantic.IMetricItem) => {
const { code, msg } = await batchDeleteTag([
{
itemIds: [metricItem.id],
tagDefineType: TAG_DEFINE_TYPE.METRIC,
},
]);
if (code === 200) {
return;
}
message.error(msg);
};
const queryBatchExportTag = async (id: number) => {
const { code, msg } = await batchCreateTag([
{ itemId: id, tagDefineType: TAG_DEFINE_TYPE.METRIC },
]);
if (code === 200) {
return;
}
message.error(msg);
};
const queryMetricsToCreateNewMetric = async () => {
const { code, data } = await getMetricsToCreateNewMetric({
modelId: modelId || metricItem?.modelId,
});
if (code === 200) {
if (Array.isArray(metricItem?.metricDefineByMetricParams?.metrics)) {
const fieldList = data.map((item: ISemantic.IMetricTypeParamsItem) => {
const { bizName } = item;
if (
metricItem?.metricDefineByMetricParams?.metrics.find(
(measureParamsItem: ISemantic.IMetricTypeParamsItem) =>
measureParamsItem.bizName === bizName,
)
) {
return {
...item,
orderNumber: 9999,
};
}
return {
...item,
orderNumber: 0,
};
});
const sortList = fieldList.sort(
(
a: ISemantic.IMetricTypeParamsItem & { orderNumber: number },
b: ISemantic.IMetricTypeParamsItem & { orderNumber: number },
) => b.orderNumber - a.orderNumber,
);
setCreateNewMetricList(sortList);
} else {
setCreateNewMetricList(data);
}
} else {
message.error('获取指标标签失败');
}
};
return (
<div>
<div
style={{
padding: '0 0 20px 24px',
// borderBottom: '1px solid #eee',
}}
>
<Radio.Group
buttonStyle="solid"
value={defineType}
onChange={(e) => {
setDefineType(e.target.value);
}}
>
<Radio.Button value={METRIC_DEFINE_TYPE.MEASURE}></Radio.Button>
<Radio.Button value={METRIC_DEFINE_TYPE.METRIC}></Radio.Button>
<Radio.Button value={METRIC_DEFINE_TYPE.FIELD}></Radio.Button>
</Radio.Group>
</div>
{defineType === METRIC_DEFINE_TYPE.MEASURE && (
<>
<MetricMeasuresFormTable
datasourceId={datasourceId}
typeParams={exprTypeParamsState[METRIC_DEFINE_TYPE.MEASURE]}
measuresList={classMeasureList}
onFieldChange={(measures: ISemantic.IMeasure[]) => {
// setClassMeasureList(measures);
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.MEASURE]: {
...prevState[METRIC_DEFINE_TYPE.MEASURE],
measures,
},
};
});
}}
onSqlChange={(expr: string) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.MEASURE]: {
...prevState[METRIC_DEFINE_TYPE.MEASURE],
expr,
},
};
});
}}
/>
</>
)}
{defineType === METRIC_DEFINE_TYPE.METRIC && (
<>
<p className={styles.desc}>
<Tag color="#2499ef14" className={styles.markerTag}>
</Tag>
</p>
<MetricMetricFormTable
typeParams={exprTypeParamsState[METRIC_DEFINE_TYPE.METRIC]}
metricList={createNewMetricList}
onFieldChange={(metrics: ISemantic.IMetricTypeParamsItem[]) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.METRIC]: {
...prevState[METRIC_DEFINE_TYPE.METRIC],
metrics,
},
};
});
}}
onSqlChange={(expr: string) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.METRIC]: {
...prevState[METRIC_DEFINE_TYPE.METRIC],
expr,
},
};
});
}}
/>
</>
)}
{defineType === METRIC_DEFINE_TYPE.FIELD && (
<>
<MetricFieldFormTable
typeParams={exprTypeParamsState[METRIC_DEFINE_TYPE.FIELD]}
fieldList={fieldList}
onFieldChange={(fields: ISemantic.IFieldTypeParamsItem[]) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.FIELD]: {
...prevState[METRIC_DEFINE_TYPE.FIELD],
fields,
},
};
});
}}
onSqlChange={(expr: string) => {
setExprTypeParamsState((prevState) => {
return {
...prevState,
[METRIC_DEFINE_TYPE.FIELD]: {
...prevState[METRIC_DEFINE_TYPE.FIELD],
expr,
},
};
});
}}
/>
</>
)}
</div>
);
};
export default MetricInfoCreateSqlConfig;

View File

@@ -0,0 +1,11 @@
export enum MetricSettingKey {
BASIC = 'BASIC',
SQL_CONFIG = 'SQLCONFIG',
DIMENSION_CONFIG = 'DIMENSION_CONFIG',
}
export const MetricSettingWording = {
[MetricSettingKey.BASIC]: '基本信息',
[MetricSettingKey.SQL_CONFIG]: '表达式',
[MetricSettingKey.DIMENSION_CONFIG]: '下钻维度配置',
};

View File

@@ -1,7 +1,12 @@
import React from 'react';
import { Outlet } from 'umi';
const market: React.FC = ({ children }) => {
return <>{children}</>;
const market: React.FC = () => {
return (
<>
<Outlet />
</>
);
};
export default market;

View File

@@ -168,6 +168,76 @@
}
}
.metricEditWrapper {
// height: calc(100vh - 56px);
// overflow: scroll;
.metricDetailTab {
:global {
.ant-tabs-nav {
margin: 10px 20px 0 20px;
padding: 0 20px;
background-color: rgb(255, 255, 255);
border-radius: 8px;
transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
}
.ant-tabs-tab {
padding: 12px 0;
color: #344767;
font-weight: 500;
}
}
}
.metricDetail {
position: relative;
display: flex;
flex-direction: row;
width: 100%;
padding: 0px;
background-color: transparent;
height: 100%;
.tabContainer {
padding: 24px;
// height: 100%;
min-height: calc(100vh - 78px);
width: calc(100vw - 350px);
background-color: #fafafb;
}
.metricInfoContent {
padding: 25px;
.title {
position: relative;
margin-bottom: 12px;
color: #0e73ff;
font-weight: bold;
font-size: 16px;
&::before {
position: absolute;
top: 10px;
left: -10px;
display: block;
width: 3px;
height: 14px;
font-size: 0;
background: #0e73ff;
border: 1px solid #0e73ff;
border-radius: 2px;
content: '';
}
}
}
.siderContainer {
width: 350px;
min-height: calc(100vh - 78px);
// margin: 10px 20px 20px 0;
// background-color: rgb(255, 255, 255);
border-radius: 6px;
padding: 24px 0 24px 24px;
// box-shadow: rgba(0, 0, 0, 0.08) 6px 0px 16px 0px, rgba(0, 0, 0, 0.12) 3px 0px 6px -4px,
// rgba(0, 0, 0, 0.05) 9px 0px 28px 8px;
}
}
}
.metricDetailWrapper {
height: calc(100vh - 56px);
overflow: scroll;
@@ -194,9 +264,12 @@
width: 100%;
padding: 0px;
background-color: transparent;
height: 100%;
.tabContainer {
height: 100%;
min-height: calc(100vh - 78px);
width: calc(100vw - 450px);
background-color: rgb(240, 242, 245);
background-color: #fafafb;
}
.metricInfoContent {
padding: 25px;
@@ -246,8 +319,19 @@
}
.metricInfoSider {
padding: 24px;
padding: 20px;
color: #344767;
background-color: #fff;
height: 100%;
border: 1px solid #e6ebf1;
border-radius: 6px;
.createTitle {
margin-bottom: 10px;
color:#344767;
font-weight: 500;
font-size: 16px;
font-family: var(--tencent-font-family);
}
.gotoMetricListIcon {
color: #3182ce;
cursor: pointer;
@@ -256,6 +340,7 @@
}
}
.title {
margin-bottom: 20px;
.name {
font-weight: 600;
font-size: 18px;
@@ -287,11 +372,16 @@
opacity: 1;
}
.sectionContainer {
margin-top: 20px;
width: 100%;
height: 100%;
position: relative;
display: flex;
flex-direction: column;
overflow: scroll;
overflow: hidden;
// box-shadow: #888888 0px 0px 1px, rgba(29, 41, 57, 0.08) 0px 1px 3px;
background-image: none;
// transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
border-radius: 6px;
.section {
padding: 16px;
@@ -420,3 +510,70 @@
}
}
}
.settingList {
list-style: none;
margin: 0px;
position: relative;
padding: 0px;
li {
-webkit-tap-highlight-color: transparent;
background-color: transparent;
outline: 0px;
border: 0px;
margin: 0px;
border-radius: 0px;
cursor: pointer;
user-select: none;
vertical-align: middle;
appearance: none;
display: flex;
flex-grow: 1;
justify-content: flex-start;
align-items: center;
position: relative;
text-decoration: none;
min-width: 0px;
box-sizing: border-box;
text-align: left;
padding: 8px 16px;
transition: background-color 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
&.active {
background-color: rgba(22, 119, 255, 0.08);
.icon {
color: rgb(22, 119, 255);
}
.content {
.text {
color: rgb(22, 119, 255);
}
}
}
.icon {
min-width: 32px;
color: #344767;
flex-shrink: 0;
display: inline-flex;
}
.content {
flex: 1 1 auto;
min-width: 0px;
margin-top: 4px;
margin-bottom: 4px;
.text {
margin: 0px;
color: #344767;
font-size: 16px;
// line-height: 1.57;
// font-family: var(--tencent-font-family);
font-weight: 600;
display: block;
}
}
&:hover {
text-decoration: none;
background-color: rgba(0, 0, 0, 0.04);
}
}
}

View File

@@ -1,31 +1,39 @@
import { Popover, message, Space } from 'antd';
import { message } from 'antd';
import React, { useEffect, useState } from 'react';
import { connect, history, useParams } from 'umi';
import { history, useParams, useModel } from '@umijs/max';
import DomainListTree from './components/DomainList';
import styles from './components/style.less';
import type { StateType } from './model';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { ISemantic } from './data';
import { getDomainList, getModelList } from './service';
// import ChatSettingTab from './ChatSetting/ChatSettingTab';
import DomainManagerTab from './components/DomainManagerTab';
import type { Dispatch } from 'umi';
type Props = {
mode: 'domain';
domainManger: StateType;
dispatch: Dispatch;
};
const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) => {
const OverviewContainer: React.FC<Props> = ({ mode }) => {
const params: any = useParams();
const domainId = params.domainId;
const modelId = params.modelId;
const domainModel = useModel('SemanticModel.domainData');
const modelModel = useModel('SemanticModel.modelData');
const dimensionModel = useModel('SemanticModel.dimensionData');
const metricModel = useModel('SemanticModel.metricData');
const databaseModel = useModel('SemanticModel.databaseData');
const { selectDomainId, domainList, setSelectDomain, setDomainList } = domainModel;
const {
selectModelId,
modelList,
MrefreshModelList,
setSelectModel,
setModelTableHistoryParams,
} = modelModel;
const { MrefreshDimensionList } = dimensionModel;
const { MrefreshMetricList } = metricModel;
const { MrefreshDatabaseList } = databaseModel;
const menuKey = params.menuKey ? params.menuKey : !Number(modelId) ? 'overview' : '';
const { selectDomainId, selectModelId, domainList } = domainManger;
const [modelList, setModelList] = useState<ISemantic.IModelItem[]>([]);
// const [modelList, setModelList] = useState<ISemantic.IModelItem[]>([]);
const [isModel, setIsModel] = useState<boolean>(false);
const [collapsedState, setCollapsedState] = useState(true);
const [activeKey, setActiveKey] = useState<string>(menuKey);
@@ -39,24 +47,13 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
return item.parentId === 0;
})[0];
if (firstRootNode) {
const { id, name } = firstRootNode;
dispatch({
type: 'domainManger/setSelectDomain',
selectDomainId: id,
selectDomainName: name,
domainData: firstRootNode,
});
const { id } = firstRootNode;
setSelectDomain(firstRootNode);
setActiveKey(menuKey);
pushUrlMenu(id, 0, menuKey);
}
} else {
const { id, name } = targetNode;
dispatch({
type: 'domainManger/setSelectDomain',
selectDomainId: id,
selectDomainName: name,
domainData: targetNode,
});
setSelectDomain(targetNode);
}
};
@@ -64,10 +61,7 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
const { code, data, msg } = await getDomainList();
if (code === 200) {
initSelectedDomain(data);
dispatch({
type: 'domainManger/setDomainList',
payload: { domainList: data },
});
setDomainList(data);
} else {
message.error(msg);
}
@@ -75,22 +69,10 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
useEffect(() => {
initProjectTree();
dispatch({
type: 'domainManger/queryDatabaseList',
});
MrefreshDatabaseList();
return () => {
dispatch({
type: 'domainManger/setSelectDomain',
selectDomainId: 0,
selectDomainName: '',
domainData: undefined,
});
dispatch({
type: 'domainManger/setSelectModel',
selectModelId: 0,
selectModelName: '',
modelData: undefined,
});
setSelectDomain(undefined);
setSelectModel(undefined);
};
}, []);
@@ -102,26 +84,15 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
}, [selectDomainId]);
const queryModelList = async () => {
const { code, data } = await getModelList(selectDomainId);
if (code === 200) {
setModelList(data);
const model = data.filter((item: any) => {
const list = await MrefreshModelList(selectDomainId);
const model = list.filter((item: any) => {
return `${item.id}` === modelId;
})[0];
if (model) {
const { id, name } = model;
dispatch({
type: 'domainManger/setSelectModel',
selectModelId: id,
selectModelName: name,
modelData: model,
});
setSelectModel(model);
setActiveKey(menuKey);
setIsModel(true);
pushUrlMenu(selectDomainId, id, menuKey);
}
} else {
message.error('获取模型列表失败!');
pushUrlMenu(model.domainId, model.id, menuKey);
}
};
@@ -144,18 +115,8 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
return;
}
initModelConfig();
dispatch({
type: 'domainManger/queryDimensionList',
payload: {
modelId: selectModelId,
},
});
dispatch({
type: 'domainManger/queryMetricList',
payload: {
modelId: selectModelId,
},
});
MrefreshDimensionList({ modelId: selectModelId });
MrefreshMetricList({ modelId: selectModelId });
}, [selectModelId]);
const pushUrlMenu = (domainId: number, modelId: number, menuKey: string) => {
@@ -163,32 +124,21 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
};
const handleModelChange = (model?: ISemantic.IModelItem) => {
// queryModelList();
console.log(model, 1111);
if (!model) {
return;
}
if (`${model.id}` === `${selectModelId}`) {
initModelConfig();
}
const { id, name } = model;
dispatch({
type: 'domainManger/setSelectModel',
selectModelId: id,
selectModelName: name,
modelData: model,
});
setSelectModel(model);
};
const cleanModelInfo = (domainId) => {
setIsModel(false);
setActiveKey('overview');
pushUrlMenu(domainId, 0, 'overview');
dispatch({
type: 'domainManger/setSelectModel',
selectModelId: 0,
selectModelName: '',
modelData: undefined,
});
setSelectModel(undefined);
};
const handleCollapsedBtn = () => {
@@ -203,19 +153,11 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
<DomainListTree
createDomainBtnVisible={mode === 'domain' ? true : false}
onTreeSelected={(domainData: ISemantic.IDomainItem) => {
const { id, name } = domainData;
const { id } = domainData;
cleanModelInfo(id);
dispatch({
type: 'domainManger/setSelectDomain',
selectDomainId: id,
selectDomainName: name,
domainData,
});
dispatch({
type: 'domainManger/setModelTableHistoryParams',
payload: {
setSelectDomain(domainData);
setModelTableHistoryParams({
[id]: {},
},
});
}}
onTreeDataUpdate={() => {
@@ -232,7 +174,6 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
>
{collapsedState ? <LeftOutlined /> : <RightOutlined />}
</div>
{/* <RightOutlined /> */}
</div>
<div className={styles.content}>
{selectDomainId ? (
@@ -243,6 +184,7 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
modelList={modelList}
handleModelChange={(model) => {
handleModelChange(model);
MrefreshModelList(selectDomainId);
}}
onBackDomainBtnClick={() => {
cleanModelInfo(selectDomainId);
@@ -262,6 +204,4 @@ const OverviewContainer: React.FC<Props> = ({ mode, domainManger, dispatch }) =>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(OverviewContainer);
export default OverviewContainer;

View File

@@ -3,26 +3,22 @@ import { Drawer } from 'antd';
import { WorkspacePanel, useXFlowApp, useModelAsync, XFlowGraphCommands } from '@antv/xflow';
import { useJsonSchemaFormModel } from '@antv/xflow-extension/es/canvas-json-schema-form/service';
import { NS_DATA_SOURCE_RELATION_MODAL_OPEN_STATE } from '../ConfigModelService';
import { connect } from 'umi';
import { DATASOURCE_NODE_RENDER_ID } from '../constant';
import DataSourceRelationFormDrawer from './DataSourceRelationFormDrawer';
import ModelCreateForm from '../../Datasource/components/ModelCreateForm';
// import ClassModelTypeModal from '../../components/ClassDataSourceTypeModal1';
import { GraphApi } from '../service';
import { SemanticNodeType } from '../../enum';
import type { StateType } from '../../model';
import DataSource from '../../Datasource';
export type CreateFormProps = {
controlMapService: any;
formSchemaService: any;
formValueUpdateService: any;
domainManger: StateType;
selectDomainId:number
};
const XflowJsonSchemaFormDrawerForm: React.FC<CreateFormProps> = (props) => {
const { domainManger } = props;
const { selectDomainId } = domainManger;
const [visible, setVisible] = useState(false);
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const [dataSourceItem, setDataSourceItem] = useState<any>();
@@ -91,7 +87,7 @@ const XflowJsonSchemaFormDrawerForm: React.FC<CreateFormProps> = (props) => {
return (
<WorkspacePanel position={{}}>
<DataSourceRelationFormDrawer
domainId={domainManger.selectDomainId}
domainId={props.selectDomainId}
nodeDataSource={nodeDataSource}
onClose={() => {
handleDataSourceRelationDrawerClose();
@@ -136,7 +132,6 @@ const XflowJsonSchemaFormDrawerForm: React.FC<CreateFormProps> = (props) => {
>
<DataSource
initialValues={dataSourceItem}
domainId={Number(domainManger?.selectDomainId)}
onSubmitSuccess={(dataSourceInfo: any) => {
setCreateModalVisible(false);
const { targetCell, targetData } = state;
@@ -174,6 +169,4 @@ const XflowJsonSchemaFormDrawerForm: React.FC<CreateFormProps> = (props) => {
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(XflowJsonSchemaFormDrawerForm);
export default XflowJsonSchemaFormDrawerForm

View File

@@ -27,8 +27,7 @@ import { useMenuConfig } from './ConfigMenu';
import { useToolbarConfig } from './ConfigToolbar';
/** 配置Dnd组件面板 */
import * as dndPanelConfig from './ConfigDndPanel';
import { connect } from 'umi';
import type { StateType } from '../model';
import { useModel } from '@umijs/max';
import './index.less';
import XflowJsonSchemaFormDrawer from './components/XflowJsonSchemaFormDrawer';
import { getViewInfoList } from '../service';
@@ -38,12 +37,17 @@ import '@antv/xflow/dist/index.css';
import { registerEdgeTool } from './ReactNodes/ToolTipsNode';
export interface IProps {
domainManger: StateType;
}
export interface IProps {}
export const SemanticFlow: React.FC<IProps> = (props) => {
const { domainManger } = props;
const domainModel = useModel('SemanticModel.domainData');
const modelModel = useModel('SemanticModel.modelData');
const { selectDomain } = domainModel;
const { selectModel } = modelModel;
const domainManger: any = {
...selectDomain,
...selectModel,
};
const graphHooksConfig = useGraphHookConfig(props);
const toolbarConfig = useToolbarConfig();
@@ -148,6 +152,4 @@ export const SemanticFlow: React.FC<IProps> = (props) => {
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(SemanticFlow);
export default SemanticFlow;

View File

@@ -1,6 +1,5 @@
import type { NsGraph } from '@antv/xflow';
import { uuidv4 } from '@antv/xflow';
import type { StateType } from '../model';
import { GraphApi } from './service';
import { NODE_WIDTH, NODE_HEIGHT } from './constant';
import moment from 'moment';
@@ -51,7 +50,7 @@ export const computedSingerNodesEdgesPosition = ({ nodes, edges }: NsGraph.IGrap
export const addClassInfoAsDataSourceParents = (
{ nodes = [], edges = [] }: NsGraph.IGraphData,
domainManger: StateType,
domainManger: any,
) => {
const { selectDomainId, selectDomainName } = domainManger;
const sourceId = `classNodeId-${selectDomainId}`;

View File

@@ -1,15 +1,11 @@
import { Space, Checkbox } from 'antd';
import type { CheckboxValueType } from 'antd/es/checkbox/Group';
import React, { useState, useEffect } from 'react';
import { connect } from 'umi';
import type { StateType } from '../../model';
import styles from '../style.less';
type Props = {
legendOptions: LegendOptionsItem[];
value?: string[];
domainManger: StateType;
onChange?: (ids: CheckboxValueType[]) => void;
defaultCheckAll?: boolean;
[key: string]: any;
@@ -78,6 +74,4 @@ const GraphLegend: React.FC<Props> = ({
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(GraphLegend);
export default GraphLegend;

View File

@@ -2,11 +2,7 @@ import { Button, Space } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import React from 'react';
import { connect } from 'umi';
import type { StateType } from '../../model';
type Props = {
domainManger: StateType;
onClick: (params?: { eventName?: string }) => void;
[key: string]: any;
};
@@ -61,6 +57,4 @@ const GraphToolBar: React.FC<Props> = ({ onClick }) => {
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(GraphToolBar);
export default GraphToolBar

View File

@@ -2,8 +2,6 @@ import { Button, Drawer, message, Row, Col, Divider, Tag, Space, Popconfirm } fr
import React, { useState, useEffect, ReactNode } from 'react';
import { SemanticNodeType } from '../../enum';
import { deleteDimension, deleteMetric, deleteDatasource } from '../../service';
import { connect } from 'umi';
import type { StateType } from '../../model';
import moment from 'moment';
import styles from '../style.less';
import TransTypeTag from '../../components/TransTypeTag';
@@ -11,7 +9,6 @@ import { SENSITIVE_LEVEL_ENUM } from '../../constant';
type Props = {
nodeData: any;
domainManger: StateType;
onNodeChange: (params?: { eventName?: string }) => void;
onEditBtnClick?: (nodeData: any) => void;
[key: string]: any;
@@ -47,13 +44,11 @@ const DescriptionItem = ({ title, content }: DescriptionItemProps) => (
const NodeInfoDrawer: React.FC<Props> = ({
nodeData,
domainManger,
onNodeChange,
onEditBtnClick,
...restProps
}) => {
const [infoList, setInfoList] = useState<InfoListItem[]>([]);
const { selectModelName } = domainManger;
useEffect(() => {
if (!nodeData) {
@@ -87,7 +82,7 @@ const NodeInfoDrawer: React.FC<Props> = ({
{
label: '所属模型',
value: modelName,
content: <Tag>{modelName || selectModelName}</Tag>,
content: <Tag>{modelName}</Tag>,
},
{
@@ -266,6 +261,4 @@ const NodeInfoDrawer: React.FC<Props> = ({
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(NodeInfoDrawer);
export default NodeInfoDrawer

View File

@@ -1,7 +1,5 @@
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'umi';
import type { StateType } from '../model';
import type { Dispatch } from 'umi';
import { useModel } from 'umi';
import {
typeConfigs,
formatterRelationData,
@@ -37,12 +35,9 @@ import GraphLegendVisibleModeItem from './components/GraphLegendVisibleModeItem'
import ModelRelationFormDrawer from './components/ModelRelationFormDrawer';
import ControlToolBar from './components/ControlToolBar';
type Props = {
domainManger: StateType;
dispatch: Dispatch;
};
type Props = {};
const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
const SemanticGraph: React.FC<Props> = ({}) => {
const ref = useRef(null);
const dataSourceRef = useRef<ISemantic.IDomainSchemaRelaList>([]);
const [graphData, setGraphData] = useState<TreeGraphData>();
@@ -63,7 +58,15 @@ const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
const [dataSourceInfoList, setDataSourceInfoList] = useState<IDataSource.IDataSourceItem[]>([]);
const { dimensionList, metricList, selectModelId: modelId, selectDomainId } = domainManger;
const domainModel = useModel('SemanticModel.domainData');
const modelModel = useModel('SemanticModel.modelData');
const dimensionModel = useModel('SemanticModel.dimensionData');
const metricModel = useModel('SemanticModel.metricData');
const { selectDomainId, selectDomainName } = domainModel;
const { selectModelId: modelId } = modelModel;
const { MdimensionList: dimensionList, MrefreshDimensionList } = dimensionModel;
const { MmetricList: metricList, MrefreshMetricList } = metricModel;
const dimensionListRef = useRef<ISemantic.IDimensionItem[]>([]);
const metricListRef = useRef<ISemantic.IMetricItem[]>([]);
@@ -134,7 +137,7 @@ const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
const graphRootData = {
id: 'root',
name: domainManger.selectDomainName,
name: selectDomainName,
children: relationData,
};
return graphRootData;
@@ -211,7 +214,6 @@ const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
const saveRelationConfig = async (domainId: number, graphData: any) => {
const configData = {
id: relationConfig?.id,
// modelId: domainManger.selectModelId,
domainId: domainId,
type: 'modelEdgeRelation',
config: JSON.stringify(graphData),
@@ -1050,20 +1052,10 @@ const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
updateGraphData();
setInfoDrawerVisible(false);
if (eventName === SemanticNodeType.METRIC) {
dispatch({
type: 'domainManger/queryMetricList',
payload: {
modelId,
},
});
MrefreshMetricList({ modelId });
}
if (eventName === SemanticNodeType.DIMENSION) {
dispatch({
type: 'domainManger/queryDimensionList',
payload: {
modelId,
},
});
MrefreshDimensionList({ modelId });
}
}}
/>
@@ -1078,12 +1070,7 @@ const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
onSubmit={() => {
setCreateDimensionModalVisible(false);
updateGraphData();
dispatch({
type: 'domainManger/queryDimensionList',
payload: {
modelId,
},
});
MrefreshDimensionList({ modelId });
}}
onCancel={() => {
setCreateDimensionModalVisible(false);
@@ -1101,12 +1088,7 @@ const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
onSubmit={() => {
setCreateMetricModalVisible(false);
updateGraphData();
dispatch({
type: 'domainManger/queryMetricList',
payload: {
modelId,
},
});
MrefreshMetricList({ modelId });
}}
onCancel={() => {
setCreateMetricModalVisible(false);
@@ -1134,18 +1116,8 @@ const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
setConfirmModalOpenState(false);
updateGraphData();
graphShowTypeState === SemanticNodeType.DIMENSION
? dispatch({
type: 'domainManger/queryDimensionList',
payload: {
modelId,
},
})
: dispatch({
type: 'domainManger/queryMetricList',
payload: {
modelId,
},
});
? MrefreshDimensionList({ modelId })
: MrefreshMetricList({ modelId });
}}
onCancelClick={() => {
setConfirmModalOpenState(false);
@@ -1154,7 +1126,7 @@ const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
/>
}
<ModelRelationFormDrawer
domainId={domainManger.selectDomainId}
domainId={selectDomainId}
nodeModel={nodeModel}
relationData={currentRelationDataItem}
onClose={() => {
@@ -1176,6 +1148,4 @@ const DomainManger: React.FC<Props> = ({ domainManger, dispatch }) => {
</>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(DomainManger);
export default SemanticGraph;

View File

@@ -8,12 +8,12 @@ import { SemanticNodeType } from './enum';
import SemanticGraph from './SemanticGraph';
type Props = {
domainManger: StateType;
};
const SemanticGraphCanvas: React.FC<Props> = ({ domainManger }) => {
const SemanticGraphCanvas: React.FC<Props> = ({ }) => {
// const [graphShowType, setGraphShowType] = useState<SemanticNodeType>(SemanticNodeType.DIMENSION);
const { selectDomainId } = domainManger;
return (
<div className={styles.semanticGraphCanvas}>
{/* <div className={styles.toolbar}>
@@ -46,6 +46,4 @@ const SemanticGraphCanvas: React.FC<Props> = ({ domainManger }) => {
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(SemanticGraphCanvas);
export default SemanticGraphCanvas;

View File

@@ -1,11 +1,9 @@
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { message, Button, Space, Popconfirm, Input, Tag } from 'antd';
import { message, Button, Space, Popconfirm } from 'antd';
import React, { useRef, useState, useEffect } from 'react';
import { StatusEnum } from '../../enum';
import type { Dispatch } from 'umi';
import { connect } from 'umi';
import type { StateType } from '../../model';
import { useModel } from '@umijs/max';
import { deleteView, updateView, getViewList, getAllModelByDomainId } from '../../service';
import ViewCreateFormModal from './ViewCreateFormModal';
import moment from 'moment';
@@ -17,12 +15,12 @@ import ViewSearchFormModal from './ViewSearchFormModal';
type Props = {
disabledEdit?: boolean;
modelList: ISemantic.IModelItem[];
dispatch: Dispatch;
domainManger: StateType;
};
const DataSetTable: React.FC<Props> = ({ disabledEdit = false, domainManger }) => {
const { selectDomainId } = domainManger;
const DataSetTable: React.FC<Props> = ({ disabledEdit = false }) => {
const domainModel = useModel('SemanticModel.domainData');
const { selectDomainId } = domainModel;
const [viewItem, setViewItem] = useState<ISemantic.IViewItem>();
const [saveLoading, setSaveLoading] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
@@ -254,6 +252,4 @@ const DataSetTable: React.FC<Props> = ({ disabledEdit = false, domainManger }) =
</>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(DataSetTable);
export default DataSetTable;

Some files were not shown because too many files have changed in this diff Show More