diff --git a/src/views/Center/components/EventFormModal.less b/src/views/Center/components/EventFormModal.less index 6b389f05..e589da52 100644 --- a/src/views/Center/components/EventFormModal.less +++ b/src/views/Center/components/EventFormModal.less @@ -1,9 +1,9 @@ -/* EventFormModal.less - 投资计划/复盘弹窗响应式样式 */ +/* EventFormModal.less - 投资计划/复盘弹窗黑金主题样式 */ // ==================== 变量定义 ==================== @mobile-breakpoint: 768px; -@modal-border-radius-mobile: 12px; -@modal-border-radius-desktop: 8px; +@modal-border-radius-mobile: 16px; +@modal-border-radius-desktop: 12px; // 间距 @spacing-xs: 4px; @@ -18,64 +18,317 @@ @font-size-sm: 14px; @font-size-md: 16px; -// 颜色 -@color-border: #f0f0f0; -@color-text-secondary: #999; -@color-error: #ff4d4f; +// 黑金主题色 +@color-bg-deep: #0A0A14; +@color-bg-primary: #0F0F1A; +@color-bg-elevated: #1A1A2E; +@color-bg-surface: #252540; +@color-bg-input: rgba(26, 26, 46, 0.8); + +@color-gold-400: #D4AF37; +@color-gold-500: #B8960C; +@color-gold-gradient: linear-gradient(135deg, #D4AF37 0%, #F5E6A3 100%); + +@color-line-subtle: rgba(212, 175, 55, 0.1); +@color-line-default: rgba(212, 175, 55, 0.2); +@color-line-emphasis: rgba(212, 175, 55, 0.4); + +@color-text-primary: rgba(255, 255, 255, 0.95); +@color-text-secondary: rgba(255, 255, 255, 0.6); +@color-text-muted: rgba(255, 255, 255, 0.4); + +@color-error: #EF4444; + +// ==================== 全局 Modal 遮罩层样式 ==================== +// 使用 rootClassName="event-form-modal-root" 来控制 mask 样式 +.event-form-modal-root { + .ant-modal-mask { + background: rgba(0, 0, 0, 0.7) !important; + backdrop-filter: blur(4px); + } + + .ant-modal-wrap { + // 确保 wrap 层也有正确的样式 + } +} // ==================== 主样式 ==================== .event-form-modal { + // Modal 整体 .ant-modal-content { + background: linear-gradient(135deg, @color-bg-elevated 0%, @color-bg-primary 100%); + border: 1px solid @color-line-default; border-radius: @modal-border-radius-desktop; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 24px rgba(212, 175, 55, 0.1); + backdrop-filter: blur(16px); } - // Modal 标题放大加粗 + // Modal 头部 + .ant-modal-header { + background: transparent; + border-bottom: 1px solid @color-line-subtle; + padding: @spacing-lg @spacing-xxl; + } + + // Modal 标题 .ant-modal-title { font-size: 20px; font-weight: 700; + background: @color-gold-gradient; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + } + + // 关闭按钮 + .ant-modal-close { + color: @color-text-secondary; + transition: all 0.3s ease; + + &:hover { + color: @color-gold-400; + background: rgba(212, 175, 55, 0.1); + } } .ant-modal-body { padding: @spacing-xxl; - padding-top: 36px; // 增加标题与表单间距 + padding-top: 24px; + } + + // Modal 底部 + .ant-modal-footer { + background: transparent; + border-top: 1px solid @color-line-subtle; + padding: @spacing-lg @spacing-xxl; } .ant-form-item { margin-bottom: @spacing-xl; } - // 表单标签加粗,左对齐 + // 表单标签 .ant-form-item-label { text-align: left !important; > label { font-weight: 600 !important; - color: #333; + color: @color-text-primary !important; + } + } + + // 输入框通用样式(支持 Ant Design v5 的 outlined 类名) + .ant-input, + .ant-input-outlined, + .ant-picker, + .ant-picker-outlined, + .ant-select-selector, + .ant-select-outlined .ant-select-selector { + background: @color-bg-input !important; + border: 1px solid @color-line-default !important; + color: @color-text-primary !important; + transition: all 0.3s ease; + + &:hover { + border-color: @color-line-emphasis !important; + background: @color-bg-input !important; + } + + &:focus, + &:focus-within, + &.ant-input-focused, + &.ant-picker-focused, + &.ant-select-focused { + border-color: @color-gold-400 !important; + box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.2) !important; + background: @color-bg-input !important; + } + + &::placeholder { + color: @color-text-muted !important; + } + } + + // 输入框 focus 状态增强 + .ant-input:focus, + .ant-input-outlined:focus, + .ant-input-affix-wrapper:focus, + .ant-input-affix-wrapper-focused { + border-color: @color-gold-400 !important; + box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.2) !important; + } + + // 输入框 wrapper + .ant-input-affix-wrapper { + background: @color-bg-input !important; + border-color: @color-line-default !important; + + .ant-input { + background: transparent !important; + } + + .ant-input-suffix { + color: @color-text-muted; + } + } + + // 输入框 placeholder + .ant-input::placeholder, + .ant-picker-input input::placeholder, + .ant-select-selection-placeholder { + color: @color-text-muted !important; + } + + // 文本域 + .ant-input-textarea, + .ant-input-textarea-show-count { + textarea, + .ant-input { + background: @color-bg-input !important; + border: 1px solid @color-line-default !important; + color: @color-text-primary !important; + + &:hover { + border-color: @color-line-emphasis !important; + background: @color-bg-input !important; + } + + &:focus { + border-color: @color-gold-400 !important; + box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.2) !important; + background: @color-bg-input !important; + } + + &::placeholder { + color: @color-text-muted !important; + } + } + } + + // 文本域 outlined 变体 + .ant-input-textarea-outlined, + textarea.ant-input-outlined { + background: @color-bg-input !important; + border: 1px solid @color-line-default !important; + color: @color-text-primary !important; + + &:hover { + border-color: @color-line-emphasis !important; + } + + &:focus { + border-color: @color-gold-400 !important; + box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.2) !important; } } // 字符计数样式 .ant-input-textarea-show-count::after { font-size: @font-size-xs; - color: @color-text-secondary; + color: @color-text-muted; } - // 日期选择器全宽 + // 日期选择器 .ant-picker { width: 100%; + + .ant-picker-input > input { + color: @color-text-primary !important; + } + + .ant-picker-suffix, + .ant-picker-clear { + color: @color-text-secondary; + } + } + + // Select 选择器 + .ant-select { + .ant-select-selector { + min-height: 38px; + background: @color-bg-input !important; + border: 1px solid @color-line-default !important; + } + + &.ant-select-focused .ant-select-selector, + &:hover .ant-select-selector { + border-color: @color-line-emphasis !important; + } + + &.ant-select-focused .ant-select-selector { + border-color: @color-gold-400 !important; + box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.2) !important; + } + + .ant-select-selection-item { + color: @color-text-primary !important; + } + + .ant-select-selection-search-input { + color: @color-text-primary !important; + } + + .ant-select-arrow { + color: @color-text-secondary; + } + + .ant-select-clear { + background: @color-bg-elevated; + color: @color-text-secondary; + + &:hover { + color: @color-gold-400; + } + } + } + + // Select 多选模式下的标签 + .ant-select-multiple .ant-select-selection-item { + background: rgba(212, 175, 55, 0.15) !important; + border: 1px solid rgba(212, 175, 55, 0.3) !important; + color: @color-gold-400 !important; + + .ant-select-selection-item-remove { + color: @color-gold-400; + + &:hover { + color: @color-text-primary; + } + } } // 股票标签样式 .ant-tag { margin: 2px; border-radius: @spacing-xs; + background: rgba(212, 175, 55, 0.15) !important; + border: 1px solid rgba(212, 175, 55, 0.3) !important; + color: @color-gold-400 !important; + + .ant-tag-close-icon { + color: @color-gold-400; + + &:hover { + color: @color-text-primary; + } + } } // 模板按钮组 .template-buttons { .ant-btn { font-size: @font-size-xs; + background: rgba(212, 175, 55, 0.1); + border: 1px solid @color-line-default; + color: @color-text-secondary; + transition: all 0.3s ease; + + &:hover { + background: rgba(212, 175, 55, 0.2); + border-color: @color-line-emphasis; + color: @color-gold-400; + } } } @@ -83,6 +336,32 @@ .modal-footer { display: flex; justify-content: flex-end; + + .ant-btn-primary { + background: linear-gradient(135deg, @color-gold-400 0%, @color-gold-500 100%); + border: none; + color: @color-bg-deep; + font-weight: 600; + height: 40px; + padding: 0 24px; + border-radius: 8px; + transition: all 0.3s ease; + + &:hover { + background: linear-gradient(135deg, lighten(@color-gold-400, 5%) 0%, lighten(@color-gold-500, 5%) 100%); + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(212, 175, 55, 0.3); + } + + &:active { + transform: translateY(0); + } + + &:disabled { + background: rgba(212, 175, 55, 0.3); + color: @color-text-muted; + } + } } // 加载状态 @@ -90,14 +369,114 @@ opacity: 0.8; } - // 错误状态动画 + // 错误状态 .ant-form-item-has-error { .ant-input, .ant-picker, .ant-select-selector { + border-color: @color-error !important; animation: shake 0.3s ease-in-out; } } + + .ant-form-item-explain-error { + color: @color-error; + } +} + +// Select 下拉菜单(挂载在 body 上,需要全局样式) +.ant-select-dropdown { + background: @color-bg-elevated !important; + border: 1px solid @color-line-default; + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + + .ant-select-item { + color: @color-text-primary; + + &:hover { + background: rgba(212, 175, 55, 0.1); + } + + &.ant-select-item-option-selected { + background: rgba(212, 175, 55, 0.2); + color: @color-gold-400; + } + + &.ant-select-item-option-active { + background: rgba(212, 175, 55, 0.15); + } + } + + .ant-select-item-empty { + color: @color-text-muted; + } + + // 分割线 + .ant-divider { + border-color: @color-line-subtle; + } + + // 提示文字 + span[style*="color: #999"] { + color: @color-text-muted !important; + } +} + +// 日期选择器下拉面板 +.ant-picker-dropdown { + .ant-picker-panel-container { + background: @color-bg-elevated; + border: 1px solid @color-line-default; + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + } + + .ant-picker-header { + color: @color-text-primary; + border-bottom: 1px solid @color-line-subtle; + + button { + color: @color-text-secondary; + + &:hover { + color: @color-gold-400; + } + } + } + + .ant-picker-content th { + color: @color-text-muted; + } + + .ant-picker-cell { + color: @color-text-secondary; + + &:hover .ant-picker-cell-inner { + background: rgba(212, 175, 55, 0.1); + } + + &.ant-picker-cell-in-view { + color: @color-text-primary; + } + + &.ant-picker-cell-selected .ant-picker-cell-inner { + background: @color-gold-400; + color: @color-bg-deep; + } + + &.ant-picker-cell-today .ant-picker-cell-inner::before { + border-color: @color-gold-400; + } + } + + .ant-picker-footer { + border-top: 1px solid @color-line-subtle; + } + + .ant-picker-today-btn { + color: @color-gold-400; + } } // ==================== 移动端适配 ==================== @@ -142,7 +521,6 @@ .ant-modal-footer { padding: @spacing-md @spacing-lg; flex-shrink: 0; - border-top: 1px solid @color-border; } // 表单项间距 @@ -182,10 +560,10 @@ } // 底部按钮 - .ant-modal-footer .ant-btn { + .modal-footer .ant-btn-primary { font-size: @font-size-md; - height: 40px; - border-radius: @spacing-sm; + height: 44px; + width: 100%; } } } diff --git a/src/views/Center/components/EventFormModal.tsx b/src/views/Center/components/EventFormModal.tsx index f22a23f7..46a16ac1 100644 --- a/src/views/Center/components/EventFormModal.tsx +++ b/src/views/Center/components/EventFormModal.tsx @@ -23,6 +23,8 @@ import { message, Space, Spin, + ConfigProvider, + theme, } from 'antd'; import type { SelectProps } from 'antd'; import { @@ -393,7 +395,7 @@ export const EventFormModal: React.FC = ({ // 判断是否显示自选股列表 const isShowingWatchlist = !searchText && stockOptions === watchlistOptions; - // 股票选择器选项配置 + // 股票选择器选项配置(黑金主题) const selectProps: SelectProps = { mode: 'multiple', placeholder: allStocksLoading ? '加载股票列表中...' : '输入股票代码或名称搜索', @@ -401,12 +403,15 @@ export const EventFormModal: React.FC = ({ onSearch: handleStockSearch, loading: watchlistLoading || allStocksLoading, notFoundContent: allStocksLoading ? ( -
+
加载中...
- ) : '暂无结果', + ) : 暂无结果, options: stockOptions, + style: { + width: '100%', + }, onFocus: () => { if (stockOptions.length === 0) { setStockOptions(watchlistOptions); @@ -416,41 +421,49 @@ export const EventFormModal: React.FC = ({ const { label: tagLabel, closable, onClose: onTagClose } = props; return ( {tagLabel} ); }, popupRender: (menu) => ( - <> +
{isShowingWatchlist && watchlistOptions.length > 0 && ( <> -
- - +
+ + 我的自选股
- + )} {menu} {!isShowingWatchlist && searchText && ( <> - -
- + +
+ 搜索结果(输入代码或名称)
)} - +
), }; @@ -462,9 +475,47 @@ export const EventFormModal: React.FC = ({ return eventType === 'plan' ? '创建计划' : '创建复盘'; }; + // 黑金主题样式 + const modalStyles = { + mask: { + background: 'rgba(0, 0, 0, 0.7)', + backdropFilter: 'blur(4px)', + }, + content: { + background: 'linear-gradient(135deg, #1A1A2E 0%, #0F0F1A 100%)', + border: '1px solid rgba(212, 175, 55, 0.2)', + borderRadius: '12px', + boxShadow: '0 8px 32px rgba(0, 0, 0, 0.5), 0 0 24px rgba(212, 175, 55, 0.1)', + }, + header: { + background: 'transparent', + borderBottom: '1px solid rgba(212, 175, 55, 0.1)', + padding: '16px 24px', + }, + body: { + padding: '24px', + paddingTop: '24px', + }, + footer: { + background: 'transparent', + borderTop: '1px solid rgba(212, 175, 55, 0.1)', + padding: '16px 24px', + }, + }; + return ( + {`${mode === 'edit' ? '编辑' : '新建'}${eventType === 'plan' ? '投资计划' : '复盘'}`} +
+ } open={isOpen} onCancel={onClose} width={600} @@ -472,25 +523,71 @@ export const EventFormModal: React.FC = ({ maskClosable={true} keyboard className="event-form-modal" + styles={modalStyles} + closeIcon={ + + } footer={ -
+
} > -
- {isOpen &&
+
+ {isOpen && = ({ {/* 标题 */} 标题 *} + label={标题 *} rules={[ { required: true, message: '请输入标题' }, { max: 50, message: '标题不能超过50个字符' }, @@ -511,17 +608,31 @@ export const EventFormModal: React.FC = ({ placeholder={getTitlePlaceholder()} maxLength={50} showCount + styles={{ + input: { + background: 'rgba(26, 26, 46, 0.8)', + borderColor: 'rgba(212, 175, 55, 0.2)', + color: 'rgba(255, 255, 255, 0.95)', + }, + count: { + color: 'rgba(255, 255, 255, 0.4)', + }, + }} /> {/* 日期 */} {eventType === 'plan' ? '计划日期' : '复盘日期'} *} + label={{eventType === 'plan' ? '计划日期' : '复盘日期'} *} rules={[{ required: true, message: '请选择日期' }]} > = ({ {/* 描述/内容 - 上下布局 */} {eventType === 'plan' ? '计划详情' : '复盘内容'} *} + label={{eventType === 'plan' ? '计划详情' : '复盘内容'} *} rules={[{ required: true, message: '请输入内容' }]} labelCol={{ span: 24 }} wrapperCol={{ span: 24 }} @@ -542,18 +653,28 @@ export const EventFormModal: React.FC = ({ rows={8} showCount maxLength={2000} - style={{ resize: 'vertical' }} + style={{ + resize: 'vertical', + background: 'rgba(26, 26, 46, 0.8)', + borderColor: 'rgba(212, 175, 55, 0.2)', + color: 'rgba(255, 255, 255, 0.95)', + }} /> {/* 模板快捷按钮 - 独立放置在 Form.Item 外部 */}
- + {templates.map((template) => ( @@ -564,12 +685,13 @@ export const EventFormModal: React.FC = ({ {/* 关联股票 */} 关联股票} + label={关联股票} >