This commit is contained in:
路 范
2021-09-24 14:33:10 +08:00
parent 0e82fb3156
commit c03092bc0c
432 changed files with 57806 additions and 4 deletions

1
Web/.env Normal file
View File

@@ -0,0 +1 @@
GENERATE_SOURCEMAP=false

1
Web/.env.development Normal file
View File

@@ -0,0 +1 @@
REACT_APP_BASE_URL=http://localhost:5566/

1
Web/.env.production Normal file
View File

@@ -0,0 +1 @@
REACT_APP_BASE_URL=http://118.178.224.202:90/

23
Web/.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

24
Web/.prettierrc.js Normal file
View File

@@ -0,0 +1,24 @@
module.exports = {
"extends": [
"airbnb",
"prettier",
"prettier/react"
],
"printWidth": 100, // 超过最大值换行
"tabWidth": 4, // 缩进字节数
"useTabs": false, // 缩进不使用tab使用空格
"semi": false, // 句尾添加分号
"singleQuote": true, // 使用单引号代替双引号
"proseWrap": "preserve", // 默认值。因为使用了一些折行敏感型的渲染器如GitHub comment而按照markdown文本样式进行折行
"arrowParens": "avoid", // (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid省略括号
"bracketSpacing": true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
"disableLanguages": ["vue"], // 不格式化vue文件vue文件的格式化单独设置
"endOfLine": "auto", // 结尾是 \n \r \n\r auto
"eslintIntegration": true, //是否让prettier使用eslint的代码格式进行校验
"htmlWhitespaceSensitivity": "ignore",
"ignorePath": ".prettierignore", // 不使用prettier格式化的文件填写在项目的.prettierignore文件中
"jsxBracketSameLine": false, // 在jsx中把'>' 单独放一行
"jsxSingleQuote": false, // 在jsx中使用单引号代替双引号
"trailingComma": "es5", // 在对象或数组最后一个元素后面是否加逗号在ES5中加尾逗号
"tslintIntegration": false // 不让prettier使用tslint的代码格式进行校验
}

70
Web/README.md Normal file
View File

@@ -0,0 +1,70 @@
# Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `yarn start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.\
You will also see any lint errors in the console.
### `yarn test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `yarn build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `yarn eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `yarn build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

35
Web/craco.config.js Normal file
View File

@@ -0,0 +1,35 @@
const CracoLessPlugin = require('craco-less')
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
module.exports = {
devServer: {
open: true,
port: 6591,
proxy: {
'/api': {
target: 'http://localhost:5566',
pathRewrite: {
'^/api': ''
}
}
}
},
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
javascriptEnabled: true,
},
},
importLoaders: 2
},
},
],
webpack: {
plugins: [
new MonacoWebpackPlugin()
]
},
}

6
Web/jsconfig.json Normal file
View File

@@ -0,0 +1,6 @@
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}

67
Web/package.json Normal file
View File

@@ -0,0 +1,67 @@
{
"name": "web-react",
"version": "0.1.0",
"private": true,
"dependencies": {
"@craco/craco": "^6.1.2",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"antd": "^4.16.2",
"axios": "^0.21.1",
"braft-editor": "^2.3.9",
"craco-less": "^1.17.1",
"crypto-js": "^4.0.0",
"echarts": "^5.1.2",
"jsencrypt": "^3.2.0",
"lodash": "^4.17.21",
"monaco-editor": "^0.25.1",
"monaco-editor-webpack-plugin": "^4.0.0",
"nprogress": "^0.2.0",
"photoswipe": "^4.1.3",
"react": "^17.0.2",
"react-color": "^2.19.3",
"react-cropper": "^2.1.8",
"react-dom": "^17.0.2",
"react-infinite-scroller": "^1.2.4",
"react-json-view": "^1.21.3",
"react-monaco-editor": "^0.43.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"redux": "^4.1.0",
"swiper": "^6.7.0",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
],
"rules": {
"eqeqeq": "off",
"no-unused-vars": "off",
"no-sparse-arrays": "off",
"array-callback-return": "off",
"jsx-a11y/anchor-is-valid": "off"
}
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

View File

@@ -0,0 +1,14 @@
export default {
/* 自定义的接口名称 */
apiName: [
/* 接口地址 */
url,
/* 请求类型 [get | post] */
'get',
/* axios所需的设置参数 */
options,
],
/* 默认为get接口 */
apiPostName: getUrl
}

View File

@@ -0,0 +1,25 @@
import { api } from 'common/api'
api.apiName(params)
.then(res => {
/* ... */
})
.catch(error => {
/* catch */
})
.finally(() => {
/* finally */
})
// 或者采用异步
async function foo() {
try {
const res = await api.apiName(params)
/* ... */
} catch (error) {
/* catch */
} finally {
/* finally */
}
}

View File

@@ -0,0 +1,35 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Application
{
// 继承PageInputBase,可以直接使用一些通用的查询和分页字段
public class DtoPageInput : Core.PageInputBase {}
// 可定义一个主键Dto
public class DtoKeyInput
{
public virtual string Id { get; set; }
}
// 可定义一个必传主键的Dto
public class DtoKeyRequiredInput : DtoKeyInput
{
[Required]
public override string Id { get; set; }
}
public class DtoAddInput
{
[MaxLength(100)]
[Required]
public string RequiredString { get; set; }
}
public class DtoUpdateInput : DtoAddInput
{
[Required]
public override string Id { get; set; }
}
public class DtoDeleteInput: DtoKeyInput {}
}

View File

@@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Ewide.Application
{
// Table特性设定表在数据库中的表名
[Table("bs_table_name")]
[Comment("表名")]
// 这里继承Core.DEntityBase,会自动添加Id及一些常用字段
public class BsTableName : Core.DEntityBase
{
// Comment特性用于生成字段说明
[Comment("字符字段")]
// MaxLength特性用于限定字段值长度,可以不设置
[MaxLength(50)]
// Required特性设置字段是否不为空
[Required]
public string StringField { get; set; }
[Comment("整形字段")]
[MaxLength(3)]
[Required]
public int IntField { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System.Threading.Tasks;
namespace Ewide.Application.Service
{
public interface Interface
{
Task<dynamic> Page(DtoPageInput input);
Task Add(DtoAddInput input);
Task Update(DtoUpdateInput input);
Task Delete(DtoDeleteInput input);
}
}

View File

@@ -0,0 +1,90 @@
using Dapper;
using Ewide.Core;
using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
namespace Ewide.Application.Service
{
[ApiDescriptionSettings(Name = "ServiceDoc")]
public class Service : Interface, IDynamicApiController, ITransient
{
// Dapper仓储
private readonly IDapperRepository _dapperRep;
// 用户信息
private readonly IUserManager _userManager;
// 数据(实体Entity)仓储
private readonly IRepository<Entity> _entityRep;
public Service(
IDapperRepository dapperRep,
IUserManager userManager,
IRepository<Entity> entityRep
)
{
_dapperRep = dapperRep;
_userManager = userManager;
_entityRep = entityRep;
}
/// <summary>
/// 查询 - EF方式
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<dynamic> Page(DtoPageInput input)
{
var data = await _entityRep.DetachedEntities.ToPageData(input);
return PageDataResult<Entity>.PageResult(data);
}
/// <summary>
/// 查询 - Dapper方式
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<dynamic> Page(DtoPageInput input)
{
var sql = "...";
var data = await _dapperRep.QueryPageDataDynamic(sql, input);
return data;
}
/// <summary>
/// 新增
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task Add(DtoAddInput input)
{
}
/// <summary>
/// 编辑
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task Update(DtoUpdateInput input)
{
}
/// <summary>
/// 删除
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task Delete(DtoDeleteInput input)
{
}
}
}

View File

@@ -0,0 +1,51 @@
import { Auth } from 'components'
import auth from 'components/authorized/handler'
/**
* 简单的权限标识
*/
function foo1() {
return (
<Auth auth="permissions:name">
<a>连接</a>
</Auth>
)
}
/**
* 多个并且关系的权限标识
*/
function foo2() {
return (
<Auth auth={['permissions:name1', 'permissions:name2']}>
<a>连接</a>
</Auth>
)
}
/**
* 多个或者关系的权限标识
*/
function foo3() {
return (
<Auth auth={[['permissions:name1'], ['permissions:name2']]}>
<a>连接</a>
</Auth>
)
}
/**
* 前缀简化
*/
function foo4() {
return (
<Auth auth={{ permissions: ['name1', 'name2'] }}>
<a>连接</a>
</Auth>
)
}
/**
* 纯js
*/
const flag = auth('permissions:name') // => Boolean

View File

@@ -0,0 +1,10 @@
import getDictData from 'util/dic'
async function foo() {
const code = await getDictData('dic_code_one', 'dic_code_two')
// =>
// code = {
// dicCodeOne: [],
// dicCodeTwo: [],
// }
}

View File

@@ -0,0 +1,32 @@
import { QueryType, getSearchDateRange, getSearchInfo } from 'util/query'
getSearchInfo({
query: {
value: '123',
text: '123',
code: 'abc',
check: ['1', '2', '3'],
range: [1, 10],
dateRange: getSearchDateRange(['2021-01-01', '2021-01-10'])
},
queryType: {
text: QueryType.Equal,
code: QueryType.Like,
check: QueryType.Equal,
range: [QueryType.GreaterThanOrEqual, QueryType.LessThan],
dateRange: [QueryType.GreaterThanOrEqual, QueryType.LessThan]
}
})
// =>
[
{ field: 'value', value: ['123'] },
{ field: 'text', value: ['123'], type: '=' },
{ field: 'code', value: ['abc'], type: 'like' },
{ field: 'check', value: ['1', '2', '3'], type: '=' },
{ field: 'range', value: [1], type: '>=' },
{ field: 'range', value: [10], type: '<' },
{ field: 'dateRange', value: ['2021-01-01'], type: '>=' },
{ field: 'dateRange', value: ['2021-01-11'], type: '<' }
]

BIN
Web/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

44
Web/public/index.html Normal file
View File

@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>宽易科技</title>
<script src="https://webapi.amap.com/maps?v=2.0&key=c6a4832b8afbde0361b36630a3fc5bdc&plugin=Map3D,AMap.DistrictSearch,AMap.Geocoder,AMap.AutoComplete,AMap.PlaceSearch"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

BIN
Web/public/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
Web/public/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

25
Web/public/manifest.json Normal file
View File

@@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
Web/public/robots.txt Normal file
View File

@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@@ -0,0 +1,153 @@
import React, { Component } from 'react'
import { Button, Tabs } from 'antd'
import { ComponentDynamic, Container } from 'components'
import { isEqual, merge } from 'lodash'
const tabs = [
{
title: '标题',
component: () => import('./tab'),
show: true,
},
]
export default class index extends Component {
state = {
actived: '0',
loading: true,
record: null,
saveDisabled: true,
saving: false,
}
// 子表单实例集合
children = []
// 整合提交数据
formData = {}
/**
* 阻止外部组件引发的渲染,提升性能
* 可自行添加渲染条件
* [必要]
* @param {*} props
* @param {*} state
* @returns
*/
shouldComponentUpdate(props, state) {
return !isEqual(this.state, state)
}
/**
* DOM加载完成钩子,可在此获取详细数据赋值到record
*/
componentDidMount() {}
/**
* 接收到所有子组件已加载完成,并启用提交按钮
*/
call(child, index) {
this.children[index] = child
if (this.children.filter(p => p).length === tabs.filter(p => p.show).length) {
this.setState({ saveDisabled: false })
}
}
async onSubmit() {
for (const child of this.children) {
try {
const data = await child.getData()
merge(this.formData, data)
} catch (e) {
return e
}
}
//#region 提交数据
this.setState({ saving: true })
this.setState({ saving: false })
//#endregion
}
render() {
const { id } = this.props
const { actived, loading, record, saveDisabled, saving } = this.state
return (
<div className="yo-form-page">
<div className="yo-form-page-layout">
{/* 底部工具栏(需放在前面) */}
<div className="yo-form-page--bar yo-form-page--bar--with-tab">
<Container mode="fluid">
<div className="yo-form-page--bar-inner">
<span></span>
<span>
<Button onClick={() => window.closeContentWindow()}>
取消
</Button>
<Button
disabled={saveDisabled}
loading={saving}
type="primary"
onClick={() => this.onSubmit()}
>
保存
</Button>
</span>
</div>
</Container>
</div>
{/* 顶部信息栏,不需要时刻删除 */}
<div className="yo-form-page--header" style={{ paddingBottom: 0 }}></div>
<div className="yo-tab-external-mount">
<Tabs
activeKey={actived}
animated={false}
onChange={activeKey => {
this.setState({ actived: activeKey })
}}
>
{tabs.map(
(tab, i) =>
tab.show && (
<Tabs.TabPane
key={i}
forceRender={false}
tab={tab.title}
></Tabs.TabPane>
)
)}
</Tabs>
<div className="yo-tab-external-mount-content">
{tabs.map((tab, i) => {
if (tab.show) {
return (
<div
key={i}
className={[
actived == i
? 'yo-tab-external-tabpane-active'
: 'yo-tab-external-tabpane-inactive',
'yo-tab-external-tabpane',
].join(' ')}
>
<ComponentDynamic
is={tab.component}
id={id}
record={record}
loading={loading}
onRef={child => this.call(child, i)}
/>
</div>
)
}
return <></>
})}
</div>
</div>
</div>
</div>
)
}
}

View File

@@ -0,0 +1,126 @@
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { Anchor, Card, Col, Divider, Row, Spin } from 'antd'
import { AntIcon, ComponentDynamic, Container } from 'components'
import { isEqual, merge } from 'lodash'
const parts = [
{
// title: '标题',
component: () => import('./part'),
},
]
export default class index extends Component {
// 子表单实例集合
children = []
// 整合提交数据
formData = {}
// 锚点挂载DOM
container = window
/**
* 阻止外部组件引发的渲染,提升性能
* 可自行添加渲染条件
* [必要]
* @param {*} props
* @param {*} state
* @returns
*/
shouldComponentUpdate(props, state) {
return !isEqual(this.state, state) || this.props.loading !== props.loading
}
/**
* 加载完成,通知父级组件并传递自身
*/
call(child, index) {
this.children[index] = child
if (this.children.filter(p => p).length === parts.length) {
const { onRef } = this.props
if (onRef) onRef(this)
}
}
/**
* 从下级组件获取表单数据,并传递给更上级组件
* [异步,必要]
* @returns
*/
async getData() {
for (const child of this.children) {
const data = await child.getData()
merge(this.formData, data)
}
return this.formData
}
/**
* 设置锚点容器
* [非必要]
* @param {*} container
*/
setContainer = container => {
this.container = (ReactDOM.findDOMNode(container) || {}).parentNode
}
/**
* 渲染
* 当前渲染结构已完善,非必要可以不用修改
* [必要]
* @returns
*/
render() {
const { id, loading } = this.props
return (
<Container mode="fluid" ref={this.setContainer}>
<Row gutter={16}>
<Col flex="1">
<br />
<div className="yo-adorn--house-top" />
<Card className="yo-form-page--body">
{parts.map((item, i) => (
<React.Fragment key={i}>
<section id={`form-${i}-${id}`}>
{item.title && <h5>{item.title}</h5>}
<Spin
spinning={loading}
indicator={<AntIcon type="loading" />}
wrapperClassName={loading && 'h-400-min'}
>
{!loading && (
<ComponentDynamic
is={item.component}
{...this.props}
onRef={child => this.call(child, i)}
/>
)}
</Spin>
</section>
{i < parts.length - 1 && <Divider />}
</React.Fragment>
))}
</Card>
</Col>
{/* 锚点,如果不需要可以删除以下节点 */}
<Col flex="240px">
<Anchor
getContainer={() => this.container}
offsetTop={24}
targetOffset={100}
wrapperStyle={{ backgroundColor: 'transparent' }}
onClick={e => e.preventDefault()}
>
{parts.map((part, i) => (
<Anchor.Link key={i} href={`#form-${i}-${id}`} title={part.title} />
))}
</Anchor>
</Col>
</Row>
</Container>
)
}
}

View File

@@ -0,0 +1,115 @@
import React, { Component } from 'react'
import { Form, Spin } from 'antd'
import { AntIcon } from 'components'
import { cloneDeep, isEqual } from 'lodash'
const initialValues = {}
const layout = {
labelCol: { flex: '150px' },
wrapperCol: { flex: '1' },
}
export default class part extends Component {
state = {
loading: true,
codes: {},
options: {},
}
// 表单实例
form = React.createRef()
// 初始化数据
record = {}
/**
* 阻止外部组件引发的渲染,提升性能
* 可自行添加渲染条件
* [必要]
* @param {*} props
* @param {*} state
* @returns
*/
shouldComponentUpdate(props, state) {
return !isEqual(this.state, state)
}
/**
* DOM加载完成钩子,绑定数据
*/
componentDidMount() {
this.fillData({
record: this.props.record,
})
}
/**
* 加载完成,通知父级组件并传递自身
*/
call() {
const { onRef } = this.props
if (onRef) onRef(this)
}
/**
* 填充数据
* 可以在设置this.record之后对其作出数据结构调整
* [异步,必要]
* @param {*} params
*/
async fillData(params) {
this.record = cloneDeep(params.record)
//#region 从后端转换成前段所需格式
//#endregion
this.form.current.setFieldsValue(this.record)
this.setState({ loading: false })
this.call()
}
/**
* 获取数据
* 可以对postData进行数据结构调整
* [异步,必要]
* @returns
*/
async getData() {
const form = this.form.current
const valid = await form.validateFields()
if (valid) {
const postData = form.getFieldsValue()
//#region 从前段转换后端所需格式
//#endregion
return postData
}
}
//#region 自定义方法
/**
* 表单change事件处理,包括了所有字段的change
* [异步,非必要]
* @param {*} changedValues
* @param {*} allValues
*/
async onValuesChange(changedValues, allValues) {}
//#endregion
render() {
const { loading } = this.state
return (
<Spin spinning={loading} indicator={<AntIcon type="loading" />}>
<Form
initialValues={initialValues}
ref={this.form}
{...layout}
onValuesChange={(changedValues, allValues) =>
this.onValuesChange(changedValues, allValues)
}
></Form>
</Spin>
)
}
}

169
Web/seed/form/index.jsx Normal file
View File

@@ -0,0 +1,169 @@
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { Anchor, Button, Card, Col, Divider, Row, Spin } from 'antd'
import { AntIcon, ComponentDynamic, Container } from 'components'
import { isEqual, merge } from 'lodash'
const parts = [
{
// title: '标题',
component: () => import('./part'),
},
]
export default class index extends Component {
state = {
loading: true,
record: null,
saveDisabled: true,
saving: false,
}
// 子表单实例集合
children = []
// 整合提交数据
formData = {}
// 锚点挂载DOM
container = window
/**
* 阻止外部组件引发的渲染,提升性能
* 可自行添加渲染条件
* [必要]
* @param {*} props
* @param {*} state
* @returns
*/
shouldComponentUpdate(props, state) {
return !isEqual(this.state, state)
}
/**
* DOM加载完成钩子,可在此获取详细数据赋值到record
*/
componentDidMount() {}
call(child, index) {
this.children[index] = child
if (this.children.filter(p => p).length === parts.filter(p => p.show).length) {
this.setState({ saveDisabled: false })
}
}
/**
* 提交
* [异步,必要]
* @returns
*/
async onSubmit() {
for (const child of this.children) {
try {
const data = await child.getData()
merge(this.formData, data)
} catch (e) {
return e
}
}
//#region 提交数据
this.setState({ saving: true })
this.setState({ saving: false })
//#endregion
}
/**
* 设置锚点容器
* [非必要]
* @param {*} container
*/
setContainer = container => {
this.container = (ReactDOM.findDOMNode(container) || {}).parentNode
}
/**
* 渲染
* 当前渲染结构已完善,非必要可以不用修改
* [必要]
* @returns
*/
render() {
const { id } = this.props
const { loading, record, saveDisabled, saving } = this.state
return (
<div className="yo-form-page">
<Container mode="fluid" ref={this.setContainer}>
<Row gutter={16}>
<Col flex="1">
<br />
<div className="yo-adorn--house-top" />
<Card className="yo-form-page--body">
{parts.map((item, i) => (
<React.Fragment key={i}>
<section id={`form-${i}-${id}`}>
{item.title && <h5>{item.title}</h5>}
<Spin
spinning={loading}
indicator={<AntIcon type="loading" />}
wrapperClassName={loading && 'h-400-min'}
>
{!loading && (
<ComponentDynamic
is={item.component}
id={id}
record={record}
onRef={child => this.call(child, i)}
/>
)}
</Spin>
</section>
{i < parts.length - 1 && <Divider />}
</React.Fragment>
))}
</Card>
</Col>
{/* 锚点,如果不需要可以删除以下节点 */}
<Col flex="240px">
<Anchor
getContainer={() => this.container}
offsetTop={24}
targetOffset={100}
wrapperStyle={{ backgroundColor: 'transparent' }}
onClick={e => e.preventDefault()}
>
{parts.map((part, i) => (
<Anchor.Link
key={i}
href={`#form-${i}-${id}`}
title={part.title}
/>
))}
</Anchor>
</Col>
</Row>
</Container>
<div className="yo-form-page--bar">
<Container mode="fluid">
<div className="yo-form-page--bar-inner">
<span></span>
<span>
<Button onClick={() => window.closeContentWindow()}>取消</Button>
<Button
disabled={saveDisabled}
loading={saving}
type="primary"
onClick={() => this.onSubmit()}
>
保存
</Button>
</span>
</div>
</Container>
</div>
</div>
)
}
}

115
Web/seed/form/part.jsx Normal file
View File

@@ -0,0 +1,115 @@
import React, { Component } from 'react'
import { Form, Spin } from 'antd'
import { AntIcon } from 'components'
import { cloneDeep, isEqual } from 'lodash'
const initialValues = {}
const layout = {
labelCol: { flex: '150px' },
wrapperCol: { flex: '1' },
}
export default class part extends Component {
state = {
loading: true,
codes: {},
options: {},
}
// 表单实例
form = React.createRef()
// 初始化数据
record = {}
/**
* 阻止外部组件引发的渲染,提升性能
* 可自行添加渲染条件
* [必要]
* @param {*} props
* @param {*} state
* @returns
*/
shouldComponentUpdate(props, state) {
return !isEqual(this.state, state)
}
/**
* DOM加载完成钩子,绑定数据
*/
componentDidMount() {
this.fillData({
record: this.props.record,
})
}
/**
* 加载完成,通知父级组件并传递自身
*/
call() {
const { onRef } = this.props
if (onRef) onRef(this)
}
/**
* 填充数据
* 可以在设置this.record之后对其作出数据结构调整
* [异步,必要]
* @param {*} params
*/
async fillData(params) {
this.record = cloneDeep(params.record)
//#region 从后端转换成前段所需格式
//#endregion
this.form.current.setFieldsValue(this.record)
this.setState({ loading: false })
this.call()
}
/**
* 获取数据
* 可以对postData进行数据结构调整
* [异步,必要]
* @returns
*/
async getData() {
const form = this.form.current
const valid = await form.validateFields()
if (valid) {
const postData = form.getFieldsValue()
//#region 从前段转换后端所需格式
//#endregion
return postData
}
}
//#region 自定义方法
/**
* 表单change事件处理,包括了所有字段的change
* [异步,非必要]
* @param {*} changedValues
* @param {*} allValues
*/
async onValuesChange(changedValues, allValues) {}
//#endregion
render() {
const { loading } = this.state
return (
<Spin spinning={loading} indicator={<AntIcon type="loading" />}>
<Form
initialValues={initialValues}
ref={this.form}
{...layout}
onValuesChange={(changedValues, allValues) =>
this.onValuesChange(changedValues, allValues)
}
></Form>
</Spin>
)
}
}

View File

@@ -0,0 +1,78 @@
import React, { Component } from 'react'
import { Form, Spin } from 'antd'
import { AntIcon } from 'components'
import { api } from 'common/api'
const initialValues = {}
export default class form extends Component {
state = {
// 加载状态
loading: true,
}
// 表单实例
form = React.createRef()
// 初始化数据
record = {}
/**
* mount后回调
*/
componentDidMount() {
this.props.created && this.props.created(this)
}
/**
* 填充数据
* 可以在设置this.record之后对其作出数据结构调整
* [异步,必要]
* @param {*} params
*/
async fillData(params) {
const state = { loading: false }
//#region 从后端转换成前段所需格式,也可以在此处调用获取详细数据接口
if (params.id) {
this.record = (await api).data
}
//#endregion
this.form.current.setFieldsValue(this.record)
this.setState(state)
}
/**
* 获取数据
* 可以对postData进行数据结构调整
* [异步,必要]
* @returns
*/
async getData() {
const form = this.form.current
const valid = await form.validateFields()
if (valid) {
const postData = form.getFieldsValue()
if (this.record) {
postData.id = this.record.id
}
//#region 从前段转换后端所需格式
//#endregion
return postData
}
}
//#region 自定义方法
//#endregion
render() {
return (
<Form initialValues={initialValues} ref={this.form} className="yo-form">
<Spin spinning={this.state.loading} indicator={<AntIcon type="loading" />}>
<div className="yo-form-group"></div>
</Spin>
</Form>
)
}
}

View File

@@ -0,0 +1,235 @@
import React, { Component } from 'react'
import { Button, Card, Form, Input, message as Message, Popconfirm } from 'antd'
import { AntIcon, Auth, Container, ModalForm, QueryTable, QueryTableActions } from 'components'
import { api } from 'common/api'
import auth from 'components/authorized/handler'
import { isEqual } from 'lodash'
import getDictData from 'util/dic'
import { toCamelCase } from 'util/format'
import FormBody from './form'
/**
* 注释段[\/**\/]为必须要改
*/
/**
* 配置页面所需接口函数
*/
const apiAction = {
page: api /**/,
add: api /**/,
edit: api /**/,
delete: api /**/,
}
/**
* 用于弹窗标题
* [必要]
*/
const name = '/**/'
/**
* 统一配置权限标识
* [必要]
*/
const authName = '/**/'
export default class index extends Component {
state = {
codes: {},
}
// 表格实例
table = React.createRef()
// 新增窗口实例
addForm = React.createRef()
// 编辑窗口实例
editForm = React.createRef()
columns = []
/**
* 构造函数,在渲染前动态添加操作字段等
* @param {*} props
*/
constructor(props) {
super(props)
const flag = auth({ [authName]: [['edit'], ['delete']] })
if (flag) {
this.columns.push({
title: '操作',
width: 150,
dataIndex: 'actions',
render: (text, { id }) => (
<QueryTableActions>
<Auth auth={{ [authName]: 'edit' }}>
<a onClick={() => this.onOpen(this.editForm, id)}>编辑</a>
</Auth>
<Auth auth={{ [authName]: 'delete' }}>
<Popconfirm
placement="topRight"
title="是否确认删除"
onConfirm={() => this.onDelete(id)}
>
<a>删除</a>
</Popconfirm>
</Auth>
</QueryTableActions>
),
})
}
}
/**
* 阻止外部组件引发的渲染,提升性能
* 可自行添加渲染条件
* [必要]
* @param {*} props
* @param {*} state
* @returns
*/
shouldComponentUpdate(props, state) {
return !isEqual(this.state, state)
}
/**
* 加载字典数据,之后开始加载表格数据
* 如果必须要加载字典数据,可直接对表格设置autoLoad=true
*/
componentDidMount() {
const { onLoading, onLoadData } = this.table.current
onLoading()
getDictData(/**/).then(codes => {
this.setState({ codes }, () => {
onLoadData()
})
})
}
/**
* 调用加载数据接口,可在调用前对query进行处理
* [异步,必要]
* @param {*} params
* @param {*} query
* @returns
*/
loadData = async (params, query) => {
const { data } = await apiAction.page({
...params,
...query,
})
return data
}
/**
* 绑定字典数据
* @param {*} code
* @param {*} name
* @returns
*/
bindCodeValue(code, name) {
name = toCamelCase(name)
const codes = this.state.codes[name]
if (codes) {
const c = codes.find(p => p.code == code)
if (c) {
return c.value
}
}
return null
}
/**
* 打开新增/编辑弹窗
* @param {*} modal
* @param {*} id
*/
onOpen(modal, id) {
modal.current.open({ id })
}
/**
* 对表格上的操作进行统一处理
* [异步]
* @param {*} action
* @param {*} successMessage
*/
async onAction(action, successMessage) {
const { onLoading, onLoaded, onReloadData } = this.table.current
onLoading()
try {
if (action) {
await action
}
if (successMessage) {
Message.success(successMessage)
}
onReloadData()
} catch {
onLoaded()
}
}
/**
* 删除
* @param {*} id
*/
onDelete(id) {
this.onAction(apiAction.delete({ id }), '删除成功')
}
//#region 自定义方法
//#endregion
render() {
return (
<Container mode="fluid">
<br />
<Card bordered={false}>
<QueryTable
ref={this.table}
autoLoad={false}
loadData={this.loadData}
columns={this.columns}
query={<Auth auth={{ [authName]: 'page' }}></Auth>}
operator={
<Auth auth={{ [authName]: 'add' }}>
<Button
icon={<AntIcon type="plus" />}
onClick={() => this.onOpen(this.addForm)}
>
新增{name}
</Button>
</Auth>
}
/>
</Card>
<Auth auth={{ [authName]: 'add' }}>
<ModalForm
title={`新增${name}`}
action={apiAction.add}
ref={this.addForm}
onSuccess={() => this.table.current.onReloadData()}
>
<FormBody />
</ModalForm>
</Auth>
<Auth auth={{ [authName]: 'edit' }}>
<ModalForm
title={`编辑${name}`}
action={apiAction.edit}
ref={this.editForm}
onSuccess={() => this.table.current.onReloadData()}
>
<FormBody />
</ModalForm>
</Auth>
</Container>
)
}
}

16
Web/src/App.js Normal file
View File

@@ -0,0 +1,16 @@
import React from 'react'
import { ConfigProvider } from 'antd'
import zhCN from 'antd/lib/locale/zh_CN'
import moment from 'moment'
import 'moment/locale/zh-cn'
moment.locale('zh-cn')
const App = () => (
<div className="app">
<ConfigProvider locale={zhCN}>
</ConfigProvider>
</div>
);
export default App

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,11 @@
@import '~antd/dist/antd.dark.less';
@padding-xxs: 4px;
@padding-xl: 32px;
body {
line-height: 1.42857143;
}
#root {
transition: @animation-duration-slow opacity;
opacity: 1 !important;
}

View File

@@ -0,0 +1,35 @@
@import './extend.less';
@import './lib/visibility.less';
@import './lib/container.less';
@import './lib/align.less';
@import './lib/font-size.less';
@import './lib/text-color.less';
@import './lib/margin.less';
@import './lib/width-height.less';
@import './lib/scrollbar.less';
@import './main.less';
@import './lib/button.less';
@import './lib/card.less';
@import './lib/table.less';
@import './lib/list.less';
@import './lib/form.less';
@import './lib/form-page.less';
@import './lib/page.less';
@import './lib/description.less';
@import './lib/input.less';
@import './lib/select.less';
@import './lib/checkbox.less';
@import './lib/radio.less';
@import './lib/cascader.less';
@import './lib/upload.less';
@import './lib/dropdown.less';
@import './lib/modal.less';
@import './lib/tree-layout.less';
@import './lib/authority-view.less';
@import './lib/icon-selector.less';
@import './lib/color-selector.less';
@import './lib/anchor.less';
@import './lib/disabled.less';
@import './theme/primary.less';
@import './public.less';
@import './pages/index.less';

View File

@@ -0,0 +1,9 @@
.text-left {
text-align: left !important;
}
.text-center {
text-align: center !important;
}
.text-right {
text-align: right !important;
}

View File

@@ -0,0 +1,11 @@
@import (reference) '../extend.less';
.ant-anchor-ink-ball {
width: 2px;
height: 28px;
transform: translate(-50%, -10px);
border: 0;
border-radius: 0;
background-color: @primary-color;
}

View File

@@ -0,0 +1,53 @@
@import (reference) '../extend.less';
.yo-authority-view {
&--container {
>.ant-descriptions-view {
border: 0;
}
}
.ant-descriptions-item-label {
width: 150px;
}
.ant-descriptions {
clear: both;
margin-bottom: @padding-sm;
.ant-descriptions-view {
overflow: visible;
}
&:last-child {
margin-bottom: 0;
}
}
.ant-descriptions-item-content {
padding: @padding-sm @padding-md;
.yo-authority-view--checkbox {
display: inline-block;
width: 150px;
margin: @padding-xxs 0;
.ant-checkbox-wrapper {
margin: 0;
}
}
}
.ant-card-grid {
width: 25%;
margin-bottom: @padding-sm;
padding: @padding-xs;
cursor: pointer;
}
.ant-card {
margin-bottom: 0;
background-color: transparent;
&-body {
margin: -1px 0 0 -1px;
padding: 0;
}
.ant-card-grid {
margin-bottom: 0;
}
}
}

View File

@@ -0,0 +1,4 @@
@import (reference) '../extend.less';
.ant-btn {
box-shadow: none;
}

View File

@@ -0,0 +1,14 @@
@import (reference) '../extend.less';
.ant-card {
margin-bottom: @padding-md;
}
.ant-card-grid-hoverable {
&:hover {
box-shadow: 1px 0 0 0 #303030,
0 1px 0 0 #303030,
1px 1px 0 0 #303030,
1px 0 0 0 #303030 inset,
0 1px 0 0 #303030 inset,
@card-shadow;
}
}

View File

@@ -0,0 +1,6 @@
@import (reference) '../extend.less';
.ant-cascader-picker-arrow {
svg {
transform: scaleY(.75);
}
}

View File

@@ -0,0 +1,10 @@
@import (reference) '../extend.less';
.ant-checkbox-wrapper {
margin-right: @padding-xs;
&:last-child {
margin-right: 0;
}
+.ant-checkbox-wrapper {
margin-left: 0;
}
}

View File

@@ -0,0 +1,18 @@
@import (reference) '../extend.less';
.ant-select-dropdown {
.chrome-picker {
width: auto !important;
margin: -@padding-xxs 0;
border-radius: 0 !important;
background: transparent !important;
box-shadow: none !important;
}
}
.color-selector--palette {
width: 32px;
height: 32px;
border-radius: @border-radius-base;
box-shadow: inset 0 0 0 @border-width-base @border-color-base, inset 0 0 0 3px @black;
}

View File

@@ -0,0 +1,43 @@
@import (reference) '../extend.less';
@container-width: 1400px;
.container-base {
margin: 0 auto;
padding: 0 @padding-md;
}
.container {
width: @container-width;
.container-base();
}
@media (max-width: 1400px) {
.container {
width: auto;
}
}
.container-md {
width: @container-width - 200px;
.container-base();
}
.container-sm {
width: @container-width - 400px;
.container-base();
}
.container-xs {
width: @container-width - 600px;
.container-base();
}
.container-xxs {
width: @container-width - 700px;
.container-base();
}
.container-fluid {
.container-base();
}
.container-flex {
display: flex;
justify-content: space-between;
}

View File

@@ -0,0 +1,10 @@
@import (reference) '../extend.less';
.ant-descriptions-bordered {
.ant-descriptions-view {
>table {
border-collapse: collapse;
background-color: @component-background;
}
}
}

View File

@@ -0,0 +1,59 @@
@import (reference) '../extend.less';
.ant-btn-primary-disabled,
.ant-btn-primary.disabled,
.ant-btn-primary[disabled],
.ant-btn-primary-disabled:hover,
.ant-btn-primary.disabled:hover,
.ant-btn-primary[disabled]:hover,
.ant-btn-primary-disabled:focus,
.ant-btn-primary.disabled:focus,
.ant-btn-primary[disabled]:focus,
.ant-btn-primary-disabled:active,
.ant-btn-primary.disabled:active,
.ant-btn-primary[disabled]:active,
.ant-btn-primary-disabled.active,
.ant-btn-primary.disabled.active,
.ant-btn-primary[disabled].active {
opacity: .5;
color: @btn-primary-color;
border-color: @btn-primary-bg;
background-color: @btn-primary-bg;
box-shadow: @btn-primary-shadow;
text-shadow: @btn-text-shadow;
}
.ant-btn-danger-disabled,
.ant-btn-danger.disabled,
.ant-btn-danger[disabled],
.ant-btn-danger-disabled:hover,
.ant-btn-danger.disabled:hover,
.ant-btn-danger[disabled]:hover,
.ant-btn-danger-disabled:focus,
.ant-btn-danger.disabled:focus,
.ant-btn-danger[disabled]:focus,
.ant-btn-danger-disabled:active,
.ant-btn-danger.disabled:active,
.ant-btn-danger[disabled]:active,
.ant-btn-danger-disabled.active,
.ant-btn-danger.disabled.active,
.ant-btn-danger[disabled].active {
opacity: .5;
color: @btn-danger-color;
border-color: @btn-danger-border;
background-color: @btn-danger-bg;
box-shadow: @btn-primary-shadow;
text-shadow: @btn-text-shadow;
}
.ant-radio-button-wrapper-disabled,
.ant-radio-button-wrapper-disabled:first-child,
.ant-radio-button-wrapper-disabled:hover {
opacity: .5;
color: @radio-button-color;
background-color: @radio-button-bg;
}
.ant-radio-button-wrapper-disabled.ant-radio-button-wrapper-checked {
opacity: .5;
color: @btn-primary-color;
border-color: @btn-primary-bg;
background-color: @btn-primary-bg;
box-shadow: @btn-primary-shadow;
}

View File

@@ -0,0 +1,6 @@
@import (reference) '../extend.less';
.ant-dropdown-trigger {
.anticon-down {
transform: scaleY(.75);
}
}

View File

@@ -0,0 +1,25 @@
@import (reference) '../extend.less';
h1,
.h1 {
font-size: 36px;
}
h2,
.h2 {
font-size: 32px;
}
h3,
.h3 {
font-size: 24px;
}
h4,
.h4 {
font-size: 18px;
}
h5,
.h5 {
font-size: 16px;
}
h6,
.h6 {
font-size: 14px;
}

View File

@@ -0,0 +1,24 @@
@import (reference) '../extend.less';
body {
font-weight: 100;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 300;
}
@btn-font-weight: 100;
.ant-card-meta-title {
font-weight: inherit;
}
.ant-table-thead {
>tr {
>th {
font-weight: 500;
}
}
}

View File

@@ -0,0 +1,169 @@
@import (reference) '../extend.less';
.yo-form-page {
position: relative;
height: 100%;
.yo-tab-external-mount {
display: flex;
flex-direction: column;
height: 100%;
>.ant-tabs {
>.ant-tabs-nav {
margin-bottom: 0;
padding: 0 @padding-md;
background-color: @component-background;
&.ant-tabs-card-bar {
.ant-tabs-nav-container {
height: @tabs-card-height + @padding-xs;
padding: (@tabs-card-height + @padding-xs - @btn-height-base) / 2 @padding-md;
}
.ant-tabs-extra-content {
padding: (@tabs-card-height + @padding-xs - @btn-height-base) / 2 @padding-md;
}
.ant-tabs-tab {
transition: none;
.ant-btn();
&:hover {
border-color: @btn-default-border;
}
}
.ant-tabs-tab {
line-height: @btn-height-base;
margin-right: -1px;
}
.ant-tabs-tab-active {
z-index: 2;
color: @btn-primary-color;
border-color: @btn-primary-bg;
background-color: @btn-primary-bg;
&:hover {
color: @btn-primary-color;
border-color: color(~`colorPalette('@{btn-primary-bg}', 5) `);
background-color: color(~`colorPalette('@{btn-primary-bg}', 5) `);
}
}
}
}
}
>.yo-tab-external-mount-content {
position: relative;
flex: 1;
>.yo-tab-external-tabpane {
position: absolute;
top: 0;
left: 0;
overflow: auto;
width: 100%;
height: 100%;
&.yo-tab-external-tabpane-inactive {
pointer-events: none;
opacity: 0;
}
}
}
}
&--bar {
position: sticky;
bottom: 0;
z-index: 200;
&--with-tab {
position: absolute;
display: flex;
align-items: flex-end;
width: 100%;
height: 0;
padding-right: 7px;
>.container-fluid {
width: 100%;
}
~.yo-tab-external-mount {
>.yo-tab-external-mount-content {
>.yo-tab-external-tabpane {
padding-bottom: @padding-xs * 2 + @btn-height-base + @border-width-base * 2;
}
}
}
}
}
&--bar-inner {
display: flex;
justify-content: space-between;
padding: @padding-xs @padding-md;
border: @border-width-base @border-style-base @border-color-split;
background-color: fade(@component-background, 80%);
backdrop-filter: blur(5px);
>:first-child {
flex: 1;
}
.ant-btn {
margin-left: @padding-sm;
}
}
&--body {
>.ant-card-body {
padding: 0;
>section {
padding: @padding-lg;
>h5 {
padding-left: @padding-md;
border-left: @padding-xs @border-style-base @primary-color;
}
}
}
}
&-layout {
display: flex;
flex-direction: column;
height: 100%;
&--horizontal {
flex-direction: row;
}
}
&--header {
padding: @padding-md 0;
background-color: @component-background;
}
}

View File

@@ -0,0 +1,401 @@
@import (reference) '../extend.less';
.yo-form {
&--fixed {
width: 660px;
margin: 0 auto;
}
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
color: darken(@white, 40%);
}
.h3 {
font-size: 16px;
}
.h4 {
font-size: 15px;
}
.yo-form-group {
margin-bottom: @padding-md;
}
.ant-form-item {
display: flex;
justify-content: space-between;
margin-bottom: -1px;
padding: @padding-xs @padding-md;
border: @border-width-base @border-style-base @border-color-split;
background-color: @component-background;
@box-shadow-focused: 0 0 0 2px fade(@primary-color, 50%);
@control-background: darken(@white, 80%) !important;
&::before,
&::after {
content: none;
}
.ant-form-item-control {
text-align: right;
}
.ant-input,
.ant-input-number,
.ant-mentions,
.ant-select-selector,
.ant-input-group-addon,
.ant-cascader-picker,
.ant-input-affix-wrapper,
.ant-picker {
z-index: 1;
text-align: left;
color: darken(@white, 10%);
border: 0;
background-color: @control-background;
}
.ant-mentions {
textarea {
background-color: @control-background;
}
}
.focus {
z-index: 2 !important;
box-shadow: @box-shadow-focused;
}
.unfoucs {
z-index: 1 !important;
box-shadow: none;
}
.ant-input {
&:focus {
.focus();
}
}
.ant-input-affix-wrapper {
>.ant-input {
&:focus {
.unfoucs();
}
}
}
.ant-input-number-focused,
.ant-mentions-focused {
.focus();
}
.ant-select-focused,
.ant-select-open {
z-index: 2;
.ant-select-selection {
.focus();
}
}
.ant-cascader-picker:focus {
.ant-cascader-input {
.focus();
}
}
.ant-input-affix-wrapper:focus,
.ant-input-affix-wrapper-focused {
.focus();
}
.ant-select-focused:not(.ant-select-disabled).ant-select:not(.ant-select-customize-input) {
.ant-select-selector {
.focus();
}
}
.ant-picker-focused {
.focus();
}
.ant-input-group {
.ant-row-flex {
.ant-select {
width: 100%;
}
}
.ant-input-group-addon {
z-index: 0;
}
}
.ant-cascader-picker-clear {
background-color: @control-background;
}
}
.ant-form-item-label {
overflow: hidden;
flex: 1 1 auto;
margin-right: @padding-md;
text-align: left;
text-overflow: ellipsis;
>label {
color: darken(@white, 10%);
&::after {
content: none;
}
}
}
.ant-form-item-control {
flex: 0 0 61.8%;
width: 61.8%;
min-width: 220px;
}
.yo-form--fluid {
.ant-form-item-control {
flex: 0 0 100%;
width: 100%;
text-align: inherit;
}
}
.yo-form--short {
.ant-form-item-control {
flex: 0 0 38.2%;
width: 38.2%;
}
}
// 上下布局
.yo-form--vertical {
display: block;
.ant-form-item-control {
text-align: left;
}
&-radio {
.ant-radio-wrapper {
line-height: @padding-lg;
display: block;
margin-right: 0;
+.ant-radio-wrapper {
margin-top: @padding-sm;
}
}
}
.ant-form-item-control-wrapper {
margin-left: @padding-lg;
}
.ant-form-explain {
margin-left: 0;
}
}
.yo-form-link {
display: flex;
align-items: center;
margin-bottom: -1px;
padding: @padding-md;
cursor: pointer;
border: @border-width-base @border-style-base @border-color-split;
background-color: @component-background;
&:hover {
background-color: lighten(@black, 1%);
}
&:active {
background-color: lighten(@black, 3%);
}
&--title {
font-size: @font-size-base + 1px;
flex: 1;
}
&--content {
flex: 1;
text-align: right;
color: fade(@black, 35%);
}
&--right-icon {
margin-left: @padding-xs;
color: fade(@black, 50%);
}
}
&.yo-form--no-border {
.ant-form-item {
padding: @padding-md 0;
border-right: 0;
border-left: 0;
&:first-child {
border-top: 0;
}
&:last-child {
border-bottom: 0;
}
}
.yo-form-group {
margin-bottom: 0;
}
}
}
.yo-modal-form {
.ant-modal-body {
padding: 0;
}
.yo-form {
h1,
h2,
h3,
h4,
h5 {
margin: 0;
padding: @padding-sm @padding-md @padding-xs;
}
.yo-form-group {
margin-bottom: 0;
}
.ant-form-item {
border-right: 0;
border-left: 0;
&:first-child {
margin-top: -1px;
}
}
}
}
.yo-drawer-form {
.ant-drawer-wrapper-body {
display: flex;
flex-direction: column;
}
.ant-drawer-header {
flex: 0 0 auto;
}
.ant-drawer-body {
position: relative;
flex: 1 1 100%;
padding: 0;
}
.yo-drawer-form--body {
position: absolute;
top: 0;
bottom: @border-width-base + 20px + @padding-md * 2;
overflow: auto;
width: 100%;
padding: @padding-lg;
}
.ant-drawer-footer {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
padding: 10px @padding-md;
text-align: right;
border-top: @border-width-base @border-style-base @border-color-split;
background: @component-background;
button+button {
margin-left: @padding-xs;
}
}
}
.ant-form {
fieldset {
margin-bottom: @padding-lg;
padding: @padding-md;
border: @border-width-base @border-style-base @border-color-split;
}
legend {
display: inline-block;
width: auto;
margin-bottom: 0;
padding: 0 @padding-md;
border: 0;
border-radius: @border-radius-base;
}
}
.ant-form-horizontal {
.ant-form-item-label {
line-height: 1.5;
margin-right: @padding-xs;
white-space: normal;
}
}
.ant-form-vertical {
.ant-form-item-label {
>label {
font-weight: bold;
}
}
}
.ant-form-item-required {
&::before {
content: '' !important;
vertical-align: middle;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 5px solid @highlight-color;
background: none;
}
}
.yo-form-page {
.ant-form {
.ant-radio-button-wrapper {
margin-right: @padding-xs;
margin-bottom: @padding-xs;
border-left: @border-width-base @border-style-base @border-color-base;
&.ant-radio-button-wrapper-checked {
border-left-color: @primary-color;
}
&:not(:first-child) {
&::before {
content: none;
}
}
}
}
}
.yo-filter-item {
display: flex;
flex-flow: row wrap;
margin-bottom: 0;
.ant-tag-checkable {
font-size: @font-size-base;
}
.ant-radio-button-wrapper {
border: 0 !important;
background-color: transparent;
&:hover {
color: @red-6;
}
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
border-color: @red-6;
background-color: @red-6;
&:hover {
border-color: @red-5;
background-color: @red-5;
}
&:active {
border-color: @red-7;
background-color: @red-7;
box-shadow: none;
}
}
}

View File

@@ -0,0 +1,59 @@
@import (reference) '../extend.less';
.yo-icon-selector {
.ant-drawer-wrapper-body {
display: flex;
flex-direction: column;
}
.ant-drawer-body {
position: relative;
flex: 1 1 100%;
padding: 0;
}
.ant-tabs {
height: 100%;
.ant-tabs-content-left {
position: relative;
height: 100%;
.ant-tabs-tabpane {
position: absolute;
top: 0;
left: 0;
overflow-y: auto;
width: 100%;
height: 100%;
padding: @padding-lg;
}
}
}
.ant-card {
margin: 0;
}
.ant-card-grid {
width: 25%;
text-align: center;
>span {
font-size: @font-size-sm;
display: block;
margin: @padding-xxs -@padding-lg 0;
white-space: nowrap;
color: fade(@black, 50%);
}
&.yo-icon--selected {
color: @white;
background-color: @primary-color;
>span {
color: fade(@white, 50%);
}
}
}
}

View File

@@ -0,0 +1,4 @@
@import (reference) '../extend.less';
.yo-addon {
padding: 0 @padding-xs;
}

View File

@@ -0,0 +1,95 @@
@import (reference) '../extend.less';
.ant-list-bordered {
border-color: @border-color-split;
background-color: @white;
}
.yo-list {
@title-color: lighten(@black, 70%);
@value-color: lighten(@black, 30%);
&-content--h {
display: flex;
align-items: center;
&--item {
margin-left: @padding-xl;
>span {
line-height: 20px;
color: @title-color;
}
>p {
line-height: 22px;
margin-top: @padding-xxs;
margin-bottom: 0;
color: @value-color;
}
}
}
.ant-pagination {
margin: @padding-md 0;
}
.ant-descriptions {
.ant-descriptions-item-label {
color: @title-color;
}
.ant-descriptions-item-content {
color: @value-color;
}
.ant-descriptions-row {
&:last-child {
>td {
padding-bottom: 0;
}
}
}
}
&--scroll {
position: relative;
overflow-x: auto;
}
.ant-list-items {
min-width: 1000px;
}
.ant-list-item {
transition: @animation-duration-slow;
transition-property: background, border-bottom-color;
&:hover {
border-bottom-color: lighten(@primary-color, 30%);
background: linear-gradient(90deg, transparent 10%, @background-color-light 70%, transparent);
}
}
&-container {
position: relative;
&::before,
&::after {
position: absolute;
top: 0;
bottom: 0;
z-index: 3;
width: 30px;
content: '';
transition: box-shadow @animation-duration-slow;
pointer-events: none;
}
&::before {
left: 0;
}
&::after {
right: 0;
}
&.yo-list--ping-left {
&::before {
box-shadow: inset 10px 0 8px -8px fade(@black, 15%);
}
}
&.yo-list--ping-right {
&::after {
box-shadow: inset -10px 0 8px -8px fade(@black, 15%);
}
}
}
}

View File

@@ -0,0 +1,68 @@
@import (reference) '../extend.less';
@margin-padding-position: ~'', ~'-top', ~'-left', ~'-right', ~'-bottom';
@margin-padding-position-name: ~'', ~'t', ~'l', ~'r', ~'b';
.margin-padding (@i) when (@i <=length(@margin-padding-position)) {
@position: extract(@margin-padding-position, @i);
@name: extract(@margin-padding-position-name, @i);
.m@{name}-xl {
margin@{position}: @padding-xl !important;
}
.m@{name}-lg {
margin@{position}: @padding-lg !important;
}
.m@{name}-md {
margin@{position}: @padding-md !important;
}
.m@{name}-sm {
margin@{position}: @padding-sm !important;
}
.m@{name}-xs {
margin@{position}: @padding-xs !important;
}
.m@{name}-xxs {
margin@{position}: @padding-xxs !important;
}
.p@{name}-xl {
padding@{position}: @padding-xl !important;
}
.p@{name}-lg {
padding@{position}: @padding-lg !important;
}
.p@{name}-md {
padding@{position}: @padding-md !important;
}
.p@{name}-sm {
padding@{position}: @padding-sm !important;
}
.p@{name}-xs {
padding@{position}: @padding-xs !important;
}
.p@{name}-xxs {
padding@{position}: @padding-xxs !important;
}
.m@{name}-none {
margin@{position}: 0 !important;
}
.p@{name}-none {
padding@{position}: 0 !important;
}
.margin-padding(@i + 1);
}
.margin-padding(1);

View File

@@ -0,0 +1,41 @@
@import (reference) '../extend.less';
.ant-modal-content {
background-color: fade(@primary-color, 50%);
backdrop-filter: blur(5px);
}
.ant-modal-header {
padding: @padding-sm @padding-md;
border-bottom: 0;
background-color: transparent;
}
.ant-modal-title {
color: fade(@white, 85%);
}
.ant-modal-body {
background-color: @component-background;
}
.ant-modal-footer {
background-color: @component-background;
}
.ant-modal-close {
top: 10px;
right: 10px;
color: fade(@white, 75%);
background-color: @error-color;
&:hover,
&:focus {
color: @white;
}
}
.ant-modal-close-x {
line-height: 26px;
width: 26px;
height: 26px;
}
.ant-modal-mask {
backdrop-filter: blur(3px);
}

View File

@@ -0,0 +1,8 @@
@import (reference) '../extend.less';
.yo-page {
&--header {
padding: @padding-md 0;
background-color: @white;
}
}

View File

@@ -0,0 +1,7 @@
@import (reference) '../extend.less';
.ant-radio-button-wrapper-checked {
&:not(.ant-radio-button-wrapper-disabled),
&:not(.ant-radio-button-wrapper-disabled):hover {
box-shadow: none;
}
}

View File

@@ -0,0 +1,14 @@
@import (reference) '../extend.less';
::-webkit-scrollbar {
width: 7px;
height: 7px;
background-color: fade(@white, 10%);
}
::-webkit-scrollbar-thumb {
border-radius: @border-radius-base;
background-color: fade(@white, 30%);
}
::-webkit-scrollbar-thumb:active {
background-color: fade(@white, 50%);
}

View File

@@ -0,0 +1,6 @@
@import (reference) '../extend.less';
.ant-select-arrow {
.anticon-down {
transform: scaleY(.75);
}
}

View File

@@ -0,0 +1,255 @@
@import (reference) '../extend.less';
.yo-query-bar {
margin-bottom: @padding-xs;
.ant-form-inline {
.ant-form-item {
margin-bottom: @padding-xs;
}
}
}
.yo-action-bar {
display: flex;
justify-content: space-between;
margin-bottom: @padding-md;
&--actions {
>.ant-btn,
>.ant-btn-group {
+.ant-btn,
+.ant-btn-group {
margin-left: @padding-xs;
}
}
}
}
.ant-table {
.ant-table-container {
&::before,
&::after {
z-index: 3;
}
}
}
.ant-table-thead {
th.ant-table-column-has-sorters {
&:hover {
background-color: darken(@background-color-base, 5%);
}
}
}
.ant-table-tbody {
>tr {
>td {
transition-property: background, border-bottom-color;
}
}
>tr.ant-table-row:hover {
>td {
border-bottom-color: lighten(@primary-color, 30%);
}
}
}
.ant-table-small {
>.ant-table-content {
>.ant-table-body {
margin: 0;
>table {
>.ant-table-thead {
>tr {
>th {
background-color: @table-selected-row-bg;
}
}
}
}
}
}
}
.ant-table-thead {
>tr {
>th {
font-weight: bold;
}
}
}
.ant-table-sticky-scroll {
display: none;
}
.ant-table-expanded-row>td {
border-right: @border-width-base @border-style-base @table-border-color !important;
}
.yo-table {
.ant-table {
margin: 0 !important;
}
.border-right-none {
border-right-width: 0 !important;
&:last-child {
border-right-width: 1px !important;
}
}
.ant-table-content {
.ant-table-body {
overflow-x: auto !important;
>table {
>.ant-table-thead {
>tr {
>th {
.border-right-none();
}
}
}
>.ant-table-tbody {
>tr {
>td {
.border-right-none();
}
}
}
}
}
.ant-table-fixed-left {
.ant-table-thead {
>tr {
>th {
border-right-width: 0 !important;
}
}
}
.ant-table-tbody {
>tr {
>td {
border-right-width: 0 !important;
}
}
}
}
.ant-table-fixed-right {
.ant-table-fixed {
border-left-width: 0 !important;
}
.ant-table-thead {
>tr {
>th {
.border-right-none();
}
}
}
.ant-table-tbody {
>tr {
>td {
.border-right-none();
}
}
}
}
}
.ant-table-bordered {
>.ant-table-container {
border-top: @border-width-base @border-style-base @table-border-color;
}
}
&--row-no {
width: 30px !important;
background-color: @table-header-bg;
}
}
.yo-table-actions {
display: inline-block;
vertical-align: middle;
&--inner {
display: flex;
align-items: center;
height: 18px;
}
}
.yo-table--column-setting {
width: 240px;
.ant-dropdown-menu-item {
display: flex;
align-items: center;
justify-content: space-between;
}
.anticon-pushpin {
transition: @animation-duration-slow;
transform: rotate(45deg);
color: darken(@white, 40%);
}
.yo-table--fixed {
transform: rotate(-45deg);
}
}
.yo-menu-table {
.ant-table {
.ant-table-expand-icon-col {
width: 28px;
}
.ant-table-row-expand-icon-cell {
z-index: 1;
padding-right: 0 !important;
border-right: none !important;
+.ant-table-cell {
padding-left: 0;
}
}
.ant-table-tbody {
>.ant-table-expanded-row>td {
padding: 0;
border-right: none !important;
.ant-table-wrapper {
margin-bottom: -1px;
border: none;
.ant-table {
margin: 0 !important;
}
.ant-table-container {
border: none;
.ant-table-row-expand-icon-cell {
.ant-table-row-expand-icon {
left: @padding-md;
}
+.ant-table-cell {
padding-left: @padding-md;
}
}
.ant-table-tbody {
>tr {
&:last-child {
>td {
border-bottom: @border-width-base @border-style-base @table-border-color;
}
&:hover {
>td {
border-bottom-color: lighten(@primary-color, 30%);
}
}
}
}
}
}
}
}
}
}
.ant-card {
max-width: fit-content;
margin: @padding-sm @padding-xs @padding-sm @padding-xl;
background: none;
.ant-card-grid {
width: 300px;
height: 90px;
padding: @padding-xs @padding-sm;
background-color: @card-background;
}
}
}

View File

@@ -0,0 +1,35 @@
@import (reference) '../extend.less';
.text-primary {
color: @primary-color !important;
}
.text-info {
color: @info-color !important;
}
.text-success {
color: @success-color !important;
}
.text-processing {
color: @processing-color !important;
}
.text-error,
.text-danger {
color: @error-color !important;
}
.text-highlight {
color: @highlight-color !important;
}
.text-warning {
color: @warning-color !important;
}
.text-gray {
color: fade(@white, 50%) !important;
}
.text-normal {
color: fade(@white, 30%) !important;
}
.text-white {
color: @white !important;
}
.text-black {
color: @black !important;
}

View File

@@ -0,0 +1,83 @@
@import (reference) '../extend.less';
@import (reference) './text-color.less';
.yo-tree-layout {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
.ant-layout-sider {
background-color: @component-background;
.ant-layout-header {
height: @layout-header-height - 20px;
background-color: @component-background;
.header-actions {
.ant-input-search {
margin: (@layout-header-height - 20px - 32px) / 2 @padding-md;
}
}
}
}
&--collapsed {
position: absolute;
top: 0;
left: 0;
bottom: 0;
z-index: 4;
transform: translateX(-100%);
&.open {
transform: translateX(0);
box-shadow: 2px 0 8px fade(@black , 20%);
}
}
&--bar {
line-height: 20px;
height: 20px;
padding: 0 @padding-md;
text-align: right;
>.anticon {
margin-left: @padding-xs;
cursor: pointer;
color: fade(@white, 50%);
&:hover {
color: fade(@white, 80%);
}
}
}
&--content {
position: absolute;
top: @layout-header-height;
left: 0;
bottom: 0;
overflow-y: auto;
width: 100%;
&::-webkit-scrollbar {
width: 5px;
height: 5px;
background-color: @component-background;
}
&::-webkit-scrollbar-thumb {
background-color: transparent;
}
&:hover::-webkit-scrollbar-thumb {
background-color: fade(@white, 30%);
}
&::-webkit-scrollbar-thumb:active {
background-color: fade(@white, 45%);
}
}
.ant-tree {
.text-gray();
}
}

View File

@@ -0,0 +1,29 @@
@import (reference) '../extend.less';
.ant-upload-list-text {
display: flex;
flex-wrap: wrap;
.ant-upload-list-item {
height: auto;
margin-right: @padding-xs;
}
.ant-upload-list-item-info {
position: relative;
padding: @padding-xxs @padding-xs;
border: @border-width-base @border-style-base @border-color-split;
.anticon-paper-clip {
top: 7.5px;
}
>span {
display: flex;
}
}
.ant-upload-list-item-card-actions {
position: relative;
margin-left: @padding-xs;
white-space: nowrap;
}
}

View File

@@ -0,0 +1,45 @@
@import (reference) '../extend.less';
.hide {
visibility: hidden !important;
}
.hidden {
display: none !important;
}
.block {
display: block;
}
.inline-block {
display: inline-block;
}
.inline {
display: inline;
}
.inline-flex {
display: inline-flex;
}
.flex {
display: flex;
}
.ellipsis {
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.ellipsis-line(@line) {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
word-break: break-all;
-webkit-line-clamp: @line;
}
.ellipsis-2 {
.ellipsis-line(2);
}
.ellipsis-3 {
.ellipsis-line(3);
}

View File

@@ -0,0 +1,47 @@
@import (reference) '../extend.less';
.width-height (@i) when (@i <=20) {
@n : @i * 50;
@px : @n * 1px;
.w-@{n} {
width: @px !important;
}
.w-@{n}-min {
min-width: @px !important;
}
.w-@{n}-max {
max-width: @px !important;
}
.h-@{n} {
height: @px !important;
}
.h-@{n}-min {
min-height: @px !important;
}
.h-@{n}-max {
max-height: @px !important;
}
.w-@{n}-p {
width: @n * 1% !important;
}
.h-@{n}-p {
height: @n * 1% !important;
}
.width-height(@i + 1);
}
.width-height(0);
.flex-1 {
flex: 1;
}

View File

@@ -0,0 +1,704 @@
@import (reference) './extend.less';
@import (reference) './lib/container.less';
@import (reference) './lib/text-color.less';
.yo-layout--spin {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: @layout-header-background;
>.ant-spin-nested-loading {
height: 100%;
>div>.ant-spin {
max-height: none;
@-webkit-keyframes borderScale {
0% {
border: 5px solid white;
}
50% {
border: 25px solid transparent;
}
100% {
border: 5px solid white;
}
}
@keyframes borderScale {
0% {
border: 5px solid white;
}
50% {
border: 25px solid transparent;
}
100% {
border: 5px solid white;
}
}
.loader-container {
position: absolute;
top: 50%;
left: 50%;
box-sizing: content-box;
width: 200px;
height: 200px;
margin: 0 auto;
margin-right: -50%;
transform: translate(-50%, -50%);
-webkit-animation: borderScale 1s infinite ease-in-out;
animation: borderScale 1s infinite ease-in-out;
color: white;
border: 5px solid transparent;
border-radius: 50%;
>p {
font-family: 'Raleway', sans-serif;
font-size: 2em;
font-weight: bold;
position: absolute;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
}
}
}
>.ant-spin-container {
width: 100%;
height: 100%;
&.ant-spin-blur {
opacity: 0;
}
}
}
}
.ant-layout-header {
.header-actions {
display: flex;
.header-action {
display: inline-block;
padding: 0 @padding-md;
cursor: pointer;
transition: @animation-duration-slow;
transition-property: background-color;
.anticon {
font-size: @font-size-base + 6px;
transition: @animation-duration-slow;
transition-property: color;
}
&:active {
box-shadow: inset 1px 1px 10px rgba(0, 0, 0, .05);
}
// 特殊工具按钮
.theme-toggle {
position: relative;
overflow: hidden;
width: 20px;
height: 20px;
margin: 7px 0;
border-radius: 50%;
&--real {
position: relative;
width: 20px;
height: 20px;
transition: @animation-duration-slow background-color;
border-radius: 50%;
background-color: fade(@white, 60%);
&::before {
position: absolute;
top: 5px;
left: 5px;
width: 10px;
height: 10px;
content: '';
transition: @animation-duration-slow transform;
transform: scale(0);
border: 2px solid @layout-header-background;
border-radius: 50%;
}
}
&--imaginary {
position: absolute;
top: 6px;
right: -6px;
width: 18px;
height: 18px;
transition: @animation-duration-slow transform;
transform: rotate(45deg) scaleY(1);
transform-origin: top right;
border-radius: 50%;
background-color: @layout-header-background;
}
}
&:hover {
.theme-toggle {
&--real {
background-color: @white;
&::before {
transform: scale(1);
}
}
&--imaginary {
transform: rotate(45deg) scaleY(0);
}
}
}
}
.ant-select-auto-complete {
margin: (@layout-header-height - 10px - 30px) / 2 @padding-md;
.ant-input-affix-wrapper {
border: 0;
background-color: fade(@white, 15%);
&:focus,
&-focused {
background-color: fade(@white, 30%);
}
.ant-input {
color: fade(@white, 85%);
background-color: transparent;
}
.ant-input-suffix {
.anticon {
color: fade(@white, 60%);
}
}
}
}
}
.user-container {
z-index: 10;
width: 32px + @padding-sm * 2;
height: @layout-header-height - 24px;
margin: 2px 0;
transition: @animation-duration-slow;
.user-container-inner {
position: relative;
transition: @animation-duration-slow;
border-radius: @border-radius-base;
}
.user {
&--base {
line-height: @layout-header-height - 24px;
position: relative;
display: flex;
overflow: hidden;
align-items: center;
width: 100%;
height: @layout-header-height - 24px;
padding: 0 @padding-sm;
transition: @animation-duration-slow;
}
&--avatar {
box-shadow: 0 0 0 2px @white;
}
}
}
}
.ant-layout-content {
position: relative;
overflow-y: auto;
>.yo-tab-external-mount {
position: absolute;
top: 0;
left: 0;
bottom: 0;
display: flex;
flex-direction: column;
width: 100%;
>.ant-tabs {
z-index: 5;
overflow: visible;
>.ant-tabs-nav {
margin-bottom: 0;
border-bottom: 0;
background-color: @layout-header-background;
box-shadow: 0 2px 12px fade(@black, 8%);
&::before {
content: none;
}
.ant-tabs-nav-container {
height: 30px;
margin-bottom: 0;
}
.ant-tabs-tab {
line-height: 30px;
height: 30px;
margin-right: 0;
padding: 0;
transition: none;
border: 0;
background-color: transparent;
&:hover {
color: @white;
}
.ant-tabs-tab-btn {
transition: none;
}
&.ant-tabs-tab-active {
border-color: darken(@primary-color, 10%);
background-color: @primary-color;
.ant-tabs-tab-btn {
color: @white;
}
.ant-tabs-tab-remove {
color: fade(@white, 70%);
&:hover {
color: @white;
}
}
}
.yo-layout-tab-subtitle {
line-height: 1;
display: inline-block;
overflow: hidden;
max-width: 150px;
transform: translateY(1px);
white-space: nowrap;
text-overflow: ellipsis;
opacity: .75;
}
+.ant-tabs-tab {
margin-left: 0;
&::before {
position: absolute;
left: -.5px;
width: 1px;
height: 24px;
content: '';
transform: scaleX(.5);
background: linear-gradient(transparent, fade(@black, 30%), transparent);
}
}
.ant-dropdown-trigger {
padding: 0 @padding-md * 2 0 @padding-md;
}
.ant-tabs-tab-unclosable {
.ant-dropdown-trigger {
padding: 0 @padding-lg 0 @padding-md;
}
}
.ant-tabs-tab-remove {
line-height: 28px;
position: absolute;
top: 0;
right: 0;
margin: 0;
transition: none;
}
}
.ant-tabs-nav-more {
padding: 5px @padding-md;
}
}
}
>.yo-tab-external-mount-content {
position: relative;
height: 100%;
>.yo-tab-external-tabpane {
position: absolute;
top: 0;
left: 0;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
height: 100%;
&.yo-tab-external-tabpane-inactive {
pointer-events: none;
opacity: 0;
}
>iframe {
display: block;
width: 100%;
height: 100%;
border: 0;
}
}
}
}
}
.ant-layout-sider {
.ant-menu-inline {
border-right: 0;
}
}
.yo-nav {
padding-top: @padding-lg;
padding-bottom: @padding-lg;
&--row {
padding: 1px 0;
column-gap: @padding-md;
column-count: 3;
}
&--col {
break-inside: avoid;
}
&--sub-item {
}
&--item-group {
font-size: @font-size-base;
line-height: 1.5;
margin-bottom: @padding-xs;
padding-top: @padding-xs * 2;
color: fade(@black, 35%);
border: @border-width-base @border-style-base transparent;
}
&--item {
font-size: @font-size-base;
line-height: 1.5;
position: relative;
margin-bottom: @padding-xs;
padding: @padding-xs @padding-sm;
cursor: pointer;
transition: @animation-duration-fast;
border: @border-width-base @border-style-base @border-color-split;
border-radius: @border-radius-base;
background-color: @white;
&:hover {
color: @white;
border-color: @primary-color;
background-color: @primary-color;
}
}
}
.yo-layout-sider {
height: 100%;
background-color: @layout-header-background;
.ant-layout-sider-children {
display: flex;
flex-direction: column;
}
.logo {
font-size: @font-size-lg * 1.5;
font-weight: 500;
line-height: @layout-header-height + 10px;
z-index: 11;
display: flex;
overflow: hidden;
align-items: center;
flex: 0 0 @layout-header-height + 10px;
height: @layout-header-height + 10px;
padding: 0 @padding-md 0 @padding-lg;
color: @white;
box-shadow: none;
img {
max-height: 100%;
}
span {
margin-left: @padding-sm;
transition: @animation-duration-slow;
transition-property: opacity;
}
}
&.ant-layout-sider-collapsed {
.logo {
span {
opacity: 0;
}
}
}
.yo-sider-nav {
position: relative;
z-index: 10;
flex: 1 1 100%;
box-shadow: 2px 0 8px fade(@black, 25%);
&--app {
font-size: @font-size-sm;
margin-top: @padding-sm;
padding: 0 @padding-md;
.text-gray();
}
.ant-menu {
background-color: @layout-header-background;
}
.ant-menu-sub.ant-menu-inline {
background-color: fade(@white, 4%);
}
}
.swiper-container {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
.swiper-scrollbar {
transition: @animation-duration-slow;
transition-property: opacity;
opacity: 0;
border-radius: @border-radius-base;
}
.swiper-scrollbar-drag {
border-radius: @border-radius-base;
background-color: fade(@white, 30%);
}
&:hover {
.swiper-scrollbar {
opacity: 1;
}
}
}
.swiper-slide {
height: auto;
min-height: 100%;
>.ant-spin-nested-loading {
height: 100%;
.ant-spin-blur {
&::after {
opacity: 0;
}
}
}
}
}
.yo-layout--left-menu,
.yo-layout--right-menu {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
.ant-layout-header {
line-height: @layout-header-height - 20px;
z-index: 6;
height: @layout-header-height - 20px;
padding: 0;
background-color: @white;
>section {
display: flex;
justify-content: space-between;
}
.header-actions {
.header-action {
line-height: @layout-header-height - 16px;
height: @layout-header-height - 20px;
color: fade(@black, 35%);
.anticon {
color: fade(@black, 35%);
}
&:hover {
color: @icon-color-hover;
background-color: fade(@black, 5%);
.anticon {
color: @icon-color-hover;
}
}
}
}
}
>section {
>.ant-layout-sider {
.yo-layout-sider();
}
}
}
.yo-layout--top-nav {
position: absolute;
top: 0;
left: 0;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
@layout-header-height: 54px;
.ant-layout-header {
line-height: @layout-header-height;
z-index: 11;
flex: 0 0 @layout-header-height;
height: @layout-header-height;
padding: 0;
background-color: @layout-header-background;
section {
display: flex;
justify-content: space-between;
height: 100%;
}
.header-actions {
.header-action {
color: fade(@white, 60%);
.anticon {
color: fade(@white, 60%);
}
&:hover {
color: @white;
background-color: fade(@white, 20%);
.anticon {
color: @white;
}
}
}
}
.user-container {
margin: (@layout-header-height - 40px) / 2 0;
}
.logo {
font-size: @font-size-lg * 1.5;
font-weight: 500;
line-height: @layout-header-height - 10px;
display: flex;
overflow: hidden;
align-items: center;
height: @layout-header-height 10px;
margin: 5px @padding-lg 5px 0;
color: @white;
img {
max-height: 100%;
}
span {
margin-left: @padding-sm;
}
}
.ant-menu-horizontal {
line-height: @layout-header-height;
border-bottom: 0;
>.ant-menu-submenu {
top: 0;
border-bottom: 0;
}
}
.header-actions {
.header-action {
line-height: @layout-header-height - 16px;
margin: 10px 0;
}
}
}
&--container {
.ant-layout-header {
.ant-menu-horizontal {
width: 400px;
}
}
.ant-layout-content {
.yo-tab-external-mount {
>.ant-tabs {
>.ant-tabs-bar {
.ant-tabs-nav-container {
width: @container-width - @padding-md * 2;
margin: 0 auto;
}
}
}
}
}
}
&--container-fluid {
.ant-layout-header {
.ant-menu-horizontal {
width: 800px;
}
@media (max-width: 1400px) {
.ant-menu-horizontal {
width: 600px;
}
}
}
}
}
.yo-user-popover {
width: 280px;
padding-top: 0;
.ant-popover-arrow {
display: none;
}
.ant-popover-inner-content {
padding: 0;
}
}
.yo-popover-infinite-scroll {
.ant-popover-inner-content {
overflow-y: auto;
max-height: 300px;
}
}

View File

@@ -0,0 +1,51 @@
@import (reference) '../extend.less';
.yo-avatar-info {
position: relative;
overflow: hidden;
width: 128px;
margin: 0 auto;
border-radius: 50%;
&--cover {
font-size: @font-size-lg * 2;
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
cursor: pointer;
transition: @animation-duration-slow;
opacity: 0;
color: @white;
background-color: fade(@black, 50%);
&:hover {
opacity: 1;
}
}
}
.yo-avatar-cropper {
overflow: hidden;
border-radius: @border-radius-base;
background-color: #ccc;
}
.yo-avatar-preview {
overflow: hidden;
width: 200px;
height: 200px;
margin: 0 auto;
border-radius: 50%;
background: #ccc;
}

View File

@@ -0,0 +1,42 @@
@import (reference) '../extend.less';
.home-header {
margin-bottom: @padding-md;
padding: @padding-lg 0;
background-color: @component-background;
}
.home-header-row {
display: flex;
}
.home-header-content {
margin-left: @padding-lg;
h4 {
span {
color: @primary-color;
}
}
p {
margin: 0;
}
}
.home-container {
.ant-card-meta-title {
font-size: @font-size-base + 1px;
display: -webkit-box;
-webkit-box-orient: vertical;
height: 42px;
white-space: normal;
-webkit-line-clamp: 2;
}
.ant-card-meta-description {
.ant-row {
line-height: 24px;
height: 24px;
}
}
}

View File

@@ -0,0 +1,3 @@
@import './login.less';
@import './home.less';
@import './account-base.less';

View File

@@ -0,0 +1,89 @@
@import (reference) '../extend.less';
.yo-login {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
>img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
&::before {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: '';
background: fade(@black, 30%) url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABZJREFUeNpiMLJ0+w8EDIwgAgQAAgwAUdAHrAFSJ6cAAAAASUVORK5CYII=);
}
&--placeholder {
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 0;
.container-sm {
display: flex;
align-items: center;
justify-content: flex-end;
height: 0;
}
}
.ant-form {
width: 300px;
padding: @padding-lg;
border-radius: @border-radius-base + 2px;
background: linear-gradient(45deg, @component-background, fade(@component-background, 80%));
}
.ant-form-item {
margin-bottom: 0;
}
.ant-form-item-label {
padding: @padding-xs 0 0 !important;
transition: @animation-duration-base;
transform: translate(0);
>label {
font-weight: normal !important;
color: fade(@white, 40%);
}
}
&--label {
.ant-form-item-label {
transform: translate(11px, 28px);
}
}
.ant-input,
.ant-input-affix-wrapper {
color: fade(@white, 85%);
border-width: 0 0 @border-width-base 0 !important;
border-color: fade(@white, 10%);
background-color: transparent;
}
.ant-input:hover,
.ant-input:focus,
.ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):hover,
.ant-input-affix-wrapper:focus,
.ant-input-affix-wrapper-focused {
border-width: 0 0 @border-width-base 0 !important;
border-color: @primary-color;
box-shadow: none !important;
}
.ant-input::placeholder {
font-size: @font-size-base;
}
}

View File

@@ -0,0 +1,45 @@
@import (reference) './extend.less';
.yo-map {
&-container {
position: relative;
padding: @padding-sm;
border: @border-width-base @border-style-base @border-color-split;
border-radius: @border-radius-base;
background-color: @component-background;
.amap-icon {
img {
width: 25px;
}
}
}
&--search {
position: absolute;
top: @padding-md;
left: @padding-md;
z-index: 20;
width: 25%;
min-width: 300px;
background-color: @component-background;
box-shadow: @box-shadow-base;
}
}
.yo-adorn {
&--house-top {
height: 65px;
background: url('~assets/image/adorn/house-top-01.png') no-repeat bottom right;
}
}
a.link-gray {
color: fade(@white, 50%);
&:hover {
color: @link-hover-color;
}
&:active {
color: @link-active-color;
}
}

View File

@@ -0,0 +1 @@
/** 在此文件夹中添加控制主题颜色的less文件 **/

View File

@@ -0,0 +1,5 @@
@import '../index.less';
@primary-color: #00a091;
@error-color: @red-7;
@font-size-base: 13px;
@border-radius-base: 0;

View File

@@ -0,0 +1,11 @@
@import '~antd/dist/antd.less';
@padding-xxs: 4px;
@padding-xl: 32px;
body {
line-height: 1.42857143;
}
#root {
transition: @animation-duration-slow opacity;
opacity: 1 !important;
}

View File

@@ -0,0 +1,36 @@
@import './extend.less';
@import './lib/visibility.less';
@import './lib/container.less';
@import './lib/align.less';
@import './lib/font-size.less';
@import './lib/text-color.less';
@import './lib/margin.less';
@import './lib/width-height.less';
@import './lib/scrollbar.less';
@import './main.less';
@import './lib/button.less';
@import './lib/card.less';
@import './lib/table.less';
@import './lib/list.less';
@import './lib/form.less';
@import './lib/form-page.less';
@import './lib/page.less';
@import './lib/description.less';
@import './lib/input.less';
@import './lib/select.less';
@import './lib/checkbox.less';
@import './lib/radio.less';
@import './lib/cascader.less';
@import './lib/upload.less';
@import './lib/dropdown.less';
@import './lib/modal.less';
@import './lib/tree-layout.less';
@import './lib/authority-view.less';
@import './lib/icon-selector.less';
@import './lib/color-selector.less';
@import './lib/anchor.less';
@import './lib/disabled.less';
@import './lib/bs.less';
@import './theme/primary.less';
@import './public.less';
@import './pages/index.less';

View File

@@ -0,0 +1,9 @@
.text-left {
text-align: left !important;
}
.text-center {
text-align: center !important;
}
.text-right {
text-align: right !important;
}

View File

@@ -0,0 +1,11 @@
@import (reference) '../extend.less';
.ant-anchor-ink-ball {
width: 2px;
height: 28px;
transform: translate(-50%, -10px);
border: 0;
border-radius: 0;
background-color: @primary-color;
}

View File

@@ -0,0 +1,53 @@
@import (reference) '../extend.less';
.yo-authority-view {
&--container {
>.ant-descriptions-view {
border: 0;
}
}
.ant-descriptions-item-label {
width: 150px;
}
.ant-descriptions {
clear: both;
margin-bottom: @padding-sm;
.ant-descriptions-view {
overflow: visible;
}
&:last-child {
margin-bottom: 0;
}
}
.ant-descriptions-item-content {
padding: @padding-sm @padding-md;
.yo-authority-view--checkbox {
display: inline-block;
width: 150px;
margin: @padding-xxs 0;
.ant-checkbox-wrapper {
margin: 0;
}
}
}
.ant-card-grid {
width: 25%;
margin-bottom: @padding-sm;
padding: @padding-xs;
cursor: pointer;
}
.ant-card {
margin-bottom: 0;
background-color: transparent;
&-body {
margin: -1px 0 0 -1px;
padding: 0;
}
.ant-card-grid {
margin-bottom: 0;
}
}
}

View File

@@ -0,0 +1,81 @@
@import (reference) '../extend.less';
.bs-list {
&-card {
background-color: @component-background;
box-shadow: inset 0 0 0 @border-width-base @border-color-split;
}
&-title {
line-height: 32px;
height: 32px;
padding: 0 @padding-lg 0 @padding-md;
color: @white;
border-top-right-radius: 999px;
border-bottom-right-radius: 999px;
background: linear-gradient(90deg, @primary-color, lighten(@primary-color, 20%));
}
&-status {
line-height: 32px;
position: relative;
height: 32px;
padding: 0 @padding-md 0 @padding-xs;
color: @white;
&::before {
position: absolute;
top: 0;
left: -20px;
content: '';
pointer-events: none;
border-top: 32px solid;
border-left: 20px solid transparent;
}
&.success {
background-color: @success-color;
&::before {
border-top-color: @success-color;
}
}
&.warning {
background-color: @warning-color;
&::before {
border-top-color: @warning-color;
}
}
&.error {
background-color: @error-color;
&::before {
border-top-color: @error-color;
}
}
}
&-body {
padding: @padding-md;
}
&-content {
display: flex;
align-items: center;
flex-wrap: nowrap;
gap: 8px;
}
&-icon {
font-size: @font-size-lg + 4px;
color: #d6e0e7;
}
&-text {
overflow: hidden;
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
color: fade(@black, 50%);
}
}

View File

@@ -0,0 +1,4 @@
@import (reference) '../extend.less';
.ant-btn {
box-shadow: none;
}

View File

@@ -0,0 +1,4 @@
@import (reference) '../extend.less';
.ant-card {
margin-bottom: @padding-md;
}

View File

@@ -0,0 +1,6 @@
@import (reference) '../extend.less';
.ant-cascader-picker-arrow {
svg {
transform: scaleY(.75);
}
}

View File

@@ -0,0 +1,10 @@
@import (reference) '../extend.less';
.ant-checkbox-wrapper {
margin-right: @padding-xs;
&:last-child {
margin-right: 0;
}
+.ant-checkbox-wrapper {
margin-left: 0;
}
}

View File

@@ -0,0 +1,18 @@
@import (reference) '../extend.less';
.ant-select-dropdown {
.chrome-picker {
width: auto !important;
margin: -@padding-xxs 0;
border-radius: 0 !important;
background: transparent !important;
box-shadow: none !important;
}
}
.color-selector--palette {
width: 32px;
height: 32px;
border-radius: @border-radius-base;
box-shadow: inset 0 0 0 @border-width-base @border-color-base, inset 0 0 0 3px @white;
}

View File

@@ -0,0 +1,43 @@
@import (reference) '../extend.less';
@container-width: 1400px;
.container-base {
margin: 0 auto;
padding: 0 @padding-md;
}
.container {
width: @container-width;
.container-base();
}
@media (max-width: 1400px) {
.container {
width: auto;
}
}
.container-md {
width: @container-width - 200px;
.container-base();
}
.container-sm {
width: @container-width - 400px;
.container-base();
}
.container-xs {
width: @container-width - 600px;
.container-base();
}
.container-xxs {
width: @container-width - 700px;
.container-base();
}
.container-fluid {
.container-base();
}
.container-flex {
display: flex;
justify-content: space-between;
}

View File

@@ -0,0 +1,10 @@
@import (reference) '../extend.less';
.ant-descriptions-bordered {
.ant-descriptions-view {
>table {
border-collapse: collapse;
background-color: @component-background;
}
}
}

View File

@@ -0,0 +1,59 @@
@import (reference) '../extend.less';
.ant-btn-primary-disabled,
.ant-btn-primary.disabled,
.ant-btn-primary[disabled],
.ant-btn-primary-disabled:hover,
.ant-btn-primary.disabled:hover,
.ant-btn-primary[disabled]:hover,
.ant-btn-primary-disabled:focus,
.ant-btn-primary.disabled:focus,
.ant-btn-primary[disabled]:focus,
.ant-btn-primary-disabled:active,
.ant-btn-primary.disabled:active,
.ant-btn-primary[disabled]:active,
.ant-btn-primary-disabled.active,
.ant-btn-primary.disabled.active,
.ant-btn-primary[disabled].active {
opacity: .5;
color: @btn-primary-color;
border-color: @btn-primary-bg;
background-color: @btn-primary-bg;
box-shadow: @btn-primary-shadow;
text-shadow: @btn-text-shadow;
}
.ant-btn-danger-disabled,
.ant-btn-danger.disabled,
.ant-btn-danger[disabled],
.ant-btn-danger-disabled:hover,
.ant-btn-danger.disabled:hover,
.ant-btn-danger[disabled]:hover,
.ant-btn-danger-disabled:focus,
.ant-btn-danger.disabled:focus,
.ant-btn-danger[disabled]:focus,
.ant-btn-danger-disabled:active,
.ant-btn-danger.disabled:active,
.ant-btn-danger[disabled]:active,
.ant-btn-danger-disabled.active,
.ant-btn-danger.disabled.active,
.ant-btn-danger[disabled].active {
opacity: .5;
color: @btn-danger-color;
border-color: @btn-danger-border;
background-color: @btn-danger-bg;
box-shadow: @btn-primary-shadow;
text-shadow: @btn-text-shadow;
}
.ant-radio-button-wrapper-disabled,
.ant-radio-button-wrapper-disabled:first-child,
.ant-radio-button-wrapper-disabled:hover {
opacity: .5;
color: @radio-button-color;
background-color: @radio-button-bg;
}
.ant-radio-button-wrapper-disabled.ant-radio-button-wrapper-checked {
opacity: .5;
color: @btn-primary-color;
border-color: @btn-primary-bg;
background-color: @btn-primary-bg;
box-shadow: @btn-primary-shadow;
}

View File

@@ -0,0 +1,6 @@
@import (reference) '../extend.less';
.ant-dropdown-trigger {
.anticon-down {
transform: scaleY(.75);
}
}

View File

@@ -0,0 +1,25 @@
@import (reference) '../extend.less';
h1,
.h1 {
font-size: 36px;
}
h2,
.h2 {
font-size: 32px;
}
h3,
.h3 {
font-size: 24px;
}
h4,
.h4 {
font-size: 18px;
}
h5,
.h5 {
font-size: 16px;
}
h6,
.h6 {
font-size: 14px;
}

View File

@@ -0,0 +1,24 @@
@import (reference) '../extend.less';
body {
font-weight: 100;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 300;
}
@btn-font-weight: 100;
.ant-card-meta-title {
font-weight: inherit;
}
.ant-table-thead {
>tr {
>th {
font-weight: 500;
}
}
}

View File

@@ -0,0 +1,169 @@
@import (reference) '../extend.less';
.yo-form-page {
position: relative;
height: 100%;
.yo-tab-external-mount {
display: flex;
flex-direction: column;
height: 100%;
>.ant-tabs {
>.ant-tabs-nav {
margin-bottom: 0;
padding: 0 @padding-md;
background-color: @component-background;
&.ant-tabs-card-bar {
.ant-tabs-nav-container {
height: @tabs-card-height + @padding-xs;
padding: (@tabs-card-height + @padding-xs - @btn-height-base) / 2 @padding-md;
}
.ant-tabs-extra-content {
padding: (@tabs-card-height + @padding-xs - @btn-height-base) / 2 @padding-md;
}
.ant-tabs-tab {
transition: none;
.ant-btn();
&:hover {
border-color: @btn-default-border;
}
}
.ant-tabs-tab {
line-height: @btn-height-base;
margin-right: -1px;
}
.ant-tabs-tab-active {
z-index: 2;
color: @btn-primary-color;
border-color: @btn-primary-bg;
background-color: @btn-primary-bg;
&:hover {
color: @btn-primary-color;
border-color: color(~`colorPalette('@{btn-primary-bg}', 5) `);
background-color: color(~`colorPalette('@{btn-primary-bg}', 5) `);
}
}
}
}
}
>.yo-tab-external-mount-content {
position: relative;
flex: 1;
>.yo-tab-external-tabpane {
position: absolute;
top: 0;
left: 0;
overflow: auto;
width: 100%;
height: 100%;
&.yo-tab-external-tabpane-inactive {
pointer-events: none;
opacity: 0;
}
}
}
}
&--bar {
position: sticky;
bottom: 0;
z-index: 200;
&--with-tab {
position: absolute;
display: flex;
align-items: flex-end;
width: 100%;
height: 0;
padding-right: 7px;
>.container-fluid {
width: 100%;
}
~.yo-tab-external-mount {
>.yo-tab-external-mount-content {
>.yo-tab-external-tabpane {
padding-bottom: @padding-xs * 2 + @btn-height-base + @border-width-base * 2;
}
}
}
}
}
&--bar-inner {
display: flex;
justify-content: space-between;
padding: @padding-xs @padding-md;
border: @border-width-base @border-style-base @border-color-split;
background-color: fade(@component-background, 80%);
backdrop-filter: blur(5px);
>:first-child {
flex: 1;
}
.ant-btn {
margin-left: @padding-sm;
}
}
&--body {
>.ant-card-body {
padding: 0;
>section {
padding: @padding-lg;
>h5 {
padding-left: @padding-md;
border-left: @padding-xs @border-style-base @primary-color;
}
}
}
}
&-layout {
display: flex;
flex-direction: column;
height: 100%;
&--horizontal {
flex-direction: row;
}
}
&--header {
padding: @padding-md 0;
background-color: @component-background;
}
}

View File

@@ -0,0 +1,401 @@
@import (reference) '../extend.less';
.yo-form {
&--fixed {
width: 660px;
margin: 0 auto;
}
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
color: darken(@white, 40%);
}
.h3 {
font-size: 16px;
}
.h4 {
font-size: 15px;
}
.yo-form-group {
margin-bottom: @padding-md;
}
.ant-form-item {
display: flex;
justify-content: space-between;
margin-bottom: -1px;
padding: @padding-xs @padding-md;
border: @border-width-base @border-style-base @border-color-split;
background-color: @component-background;
@box-shadow-focused: 0 0 0 2px fade(@primary-color, 50%);
@control-background: lighten(@black, 95%) !important;
&::before,
&::after {
content: none;
}
.ant-form-item-control {
text-align: right;
}
.ant-input,
.ant-input-number,
.ant-mentions,
.ant-select-selector,
.ant-input-group-addon,
.ant-cascader-picker,
.ant-input-affix-wrapper,
.ant-picker {
z-index: 1;
text-align: left;
color: lighten(@black, 10%);
border: 0;
background-color: @control-background;
}
.ant-mentions {
textarea {
background-color: @control-background;
}
}
.focus {
z-index: 2 !important;
box-shadow: @box-shadow-focused;
}
.unfoucs {
z-index: 1 !important;
box-shadow: none;
}
.ant-input {
&:focus {
.focus();
}
}
.ant-input-affix-wrapper {
>.ant-input {
&:focus {
.unfoucs();
}
}
}
.ant-input-number-focused,
.ant-mentions-focused {
.focus();
}
.ant-select-focused,
.ant-select-open {
z-index: 2;
.ant-select-selection {
.focus();
}
}
.ant-cascader-picker:focus {
.ant-cascader-input {
.focus();
}
}
.ant-input-affix-wrapper:focus,
.ant-input-affix-wrapper-focused {
.focus();
}
.ant-select-focused:not(.ant-select-disabled).ant-select:not(.ant-select-customize-input) {
.ant-select-selector {
.focus();
}
}
.ant-picker-focused {
.focus();
}
.ant-input-group {
.ant-row-flex {
.ant-select {
width: 100%;
}
}
.ant-input-group-addon {
z-index: 0;
}
}
.ant-cascader-picker-clear {
background-color: @control-background;
}
}
.ant-form-item-label {
overflow: hidden;
flex: 1 1 auto;
margin-right: @padding-md;
text-align: left;
text-overflow: ellipsis;
>label {
color: lighten(@black, 10%);
&::after {
content: none;
}
}
}
.ant-form-item-control {
flex: 0 0 61.8%;
width: 61.8%;
min-width: 220px;
}
.yo-form--fluid {
.ant-form-item-control {
flex: 0 0 100%;
width: 100%;
text-align: inherit;
}
}
.yo-form--short {
.ant-form-item-control {
flex: 0 0 38.2%;
width: 38.2%;
}
}
// 上下布局
.yo-form--vertical {
display: block;
.ant-form-item-control {
text-align: left;
}
&-radio {
.ant-radio-wrapper {
line-height: @padding-lg;
display: block;
margin-right: 0;
+.ant-radio-wrapper {
margin-top: @padding-sm;
}
}
}
.ant-form-item-control-wrapper {
margin-left: @padding-lg;
}
.ant-form-explain {
margin-left: 0;
}
}
.yo-form-link {
display: flex;
align-items: center;
margin-bottom: -1px;
padding: @padding-md;
cursor: pointer;
border: @border-width-base @border-style-base @border-color-split;
background-color: @white;
&:hover {
background-color: darken(@white, 1%);
}
&:active {
background-color: darken(@white, 3%);
}
&--title {
font-size: @font-size-base + 1px;
flex: 1;
}
&--content {
flex: 1;
text-align: right;
color: fade(@black, 35%);
}
&--right-icon {
margin-left: @padding-xs;
color: fade(@black, 50%);
}
}
&.yo-form--no-border {
.ant-form-item {
padding: @padding-md 0;
border-right: 0;
border-left: 0;
&:first-child {
border-top: 0;
}
&:last-child {
border-bottom: 0;
}
}
.yo-form-group {
margin-bottom: 0;
}
}
}
.yo-modal-form {
.ant-modal-body {
padding: 0;
}
.yo-form {
h1,
h2,
h3,
h4,
h5 {
margin: 0;
padding: @padding-sm @padding-md @padding-xs;
}
.yo-form-group {
margin-bottom: 0;
}
.ant-form-item {
border-right: 0;
border-left: 0;
&:first-child {
margin-top: -1px;
}
}
}
}
.yo-drawer-form {
.ant-drawer-wrapper-body {
display: flex;
flex-direction: column;
}
.ant-drawer-header {
flex: 0 0 auto;
}
.ant-drawer-body {
position: relative;
flex: 1 1 100%;
padding: 0;
}
.yo-drawer-form--body {
position: absolute;
top: 0;
bottom: @border-width-base + 20px + @padding-md * 2;
overflow: auto;
width: 100%;
padding: @padding-lg;
}
.ant-drawer-footer {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
padding: 10px @padding-md;
text-align: right;
border-top: @border-width-base @border-style-base @border-color-split;
background: @component-background;
button+button {
margin-left: @padding-xs;
}
}
}
.ant-form {
fieldset {
margin-bottom: @padding-lg;
padding: @padding-md;
border: @border-width-base @border-style-base @border-color-split;
}
legend {
display: inline-block;
width: auto;
margin-bottom: 0;
padding: 0 @padding-md;
border: 0;
border-radius: @border-radius-base;
}
}
.ant-form-horizontal {
.ant-form-item-label {
line-height: 1.5;
margin-right: @padding-xs;
white-space: normal;
}
}
.ant-form-vertical {
.ant-form-item-label {
>label {
font-weight: bold;
}
}
}
.ant-form-item-required {
&::before {
content: '' !important;
vertical-align: middle;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 5px solid @highlight-color;
background: none;
}
}
.yo-form-page {
.ant-form {
.ant-radio-button-wrapper {
margin-right: @padding-xs;
margin-bottom: @padding-xs;
border-left: @border-width-base @border-style-base @border-color-base;
&.ant-radio-button-wrapper-checked {
border-left-color: @primary-color;
}
&:not(:first-child) {
&::before {
content: none;
}
}
}
}
}
.yo-filter-item {
display: flex;
flex-flow: row wrap;
margin-bottom: 0;
.ant-tag-checkable {
font-size: @font-size-base;
}
.ant-radio-button-wrapper {
border: 0 !important;
background-color: transparent;
&:hover {
color: @red-6;
}
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
border-color: @red-6;
background-color: @red-6;
&:hover {
border-color: @red-5;
background-color: @red-5;
}
&:active {
border-color: @red-7;
background-color: @red-7;
box-shadow: none;
}
}
}

View File

@@ -0,0 +1,59 @@
@import (reference) '../extend.less';
.yo-icon-selector {
.ant-drawer-wrapper-body {
display: flex;
flex-direction: column;
}
.ant-drawer-body {
position: relative;
flex: 1 1 100%;
padding: 0;
}
.ant-tabs {
height: 100%;
.ant-tabs-content-left {
position: relative;
height: 100%;
.ant-tabs-tabpane {
position: absolute;
top: 0;
left: 0;
overflow-y: auto;
width: 100%;
height: 100%;
padding: @padding-lg;
}
}
}
.ant-card {
margin: 0;
}
.ant-card-grid {
width: 25%;
text-align: center;
>span {
font-size: @font-size-sm;
display: block;
margin: @padding-xxs -@padding-lg 0;
white-space: nowrap;
color: fade(@black, 50%);
}
&.yo-icon--selected {
color: @white;
background-color: @primary-color;
>span {
color: fade(@white, 50%);
}
}
}
}

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