style:1.组织管理页面支持组织列表滚动 2.优化一些页面的标题和图标显示
This commit is contained in:
@@ -283,7 +283,10 @@ export default function Careers() {
|
||||
flexWrap: 'wrap',
|
||||
gap: '12px'
|
||||
}}>
|
||||
<Title level={3} style={{ margin: 0 }}>职业管理</Title>
|
||||
<Title level={3} style={{ margin: 0 }}>
|
||||
<TrophyOutlined style={{ marginRight: 8 }} />
|
||||
职业管理
|
||||
</Title>
|
||||
<Space wrap>
|
||||
<Button
|
||||
type="dashed"
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
LeftOutlined,
|
||||
RightOutlined,
|
||||
UnorderedListOutlined,
|
||||
FundOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import api from '../services/api';
|
||||
@@ -189,14 +190,30 @@ const ChapterAnalysis: React.FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
height: '100%',
|
||||
gap: isMobile ? 0 : 16,
|
||||
flexDirection: isMobile ? 'column' : 'row'
|
||||
}}>
|
||||
{/* 左侧章节列表 - 桌面端 */}
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
{/* 页面标题 - 仅桌面端显示 */}
|
||||
{!isMobile && (
|
||||
<div style={{
|
||||
padding: '16px 0',
|
||||
marginBottom: 16,
|
||||
borderBottom: '1px solid #f0f0f0'
|
||||
}}>
|
||||
<h2 style={{ margin: 0, fontSize: 24 }}>
|
||||
<FundOutlined style={{ marginRight: 8 }} />
|
||||
剧情分析
|
||||
</h2>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
gap: isMobile ? 0 : 16,
|
||||
flexDirection: isMobile ? 'column' : 'row',
|
||||
overflow: 'hidden'
|
||||
}}>
|
||||
{/* 左侧章节列表 - 桌面端 */}
|
||||
{!isMobile && (
|
||||
<Card
|
||||
title="章节列表"
|
||||
style={{ width: 280, height: '100%', overflow: 'hidden' }}
|
||||
@@ -237,9 +254,9 @@ const ChapterAnalysis: React.FC = () => {
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
)}
|
||||
)}
|
||||
|
||||
{/* 移动端章节列表抽屉 */}
|
||||
{/* 移动端章节列表抽屉 */}
|
||||
{isMobile && (
|
||||
<Drawer
|
||||
title="章节列表"
|
||||
@@ -284,10 +301,10 @@ const ChapterAnalysis: React.FC = () => {
|
||||
/>
|
||||
)}
|
||||
</Drawer>
|
||||
)}
|
||||
)}
|
||||
|
||||
{/* 右侧内容区域 */}
|
||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
|
||||
{/* 右侧内容区域 */}
|
||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
|
||||
{!selectedChapter ? (
|
||||
<Card style={{ height: '100%' }}>
|
||||
<Empty description="请从左侧选择一个章节查看" style={{ marginTop: 100 }} />
|
||||
@@ -530,6 +547,7 @@ const ChapterAnalysis: React.FC = () => {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1491,7 +1491,10 @@ export default function Chapters() {
|
||||
justifyContent: 'space-between',
|
||||
alignItems: isMobile ? 'stretch' : 'center'
|
||||
}}>
|
||||
<h2 style={{ margin: 0, fontSize: isMobile ? 18 : 24 }}>章节管理</h2>
|
||||
<h2 style={{ margin: 0, fontSize: isMobile ? 18 : 24 }}>
|
||||
<BookOutlined style={{ marginRight: 8 }} />
|
||||
章节管理
|
||||
</h2>
|
||||
<Space direction={isMobile ? 'vertical' : 'horizontal'} style={{ width: isMobile ? '100%' : 'auto' }}>
|
||||
{currentProject.outline_mode === 'one-to-many' && (
|
||||
<Button
|
||||
|
||||
@@ -382,7 +382,10 @@ export default function Characters() {
|
||||
justifyContent: 'space-between',
|
||||
alignItems: isMobile ? 'stretch' : 'center'
|
||||
}}>
|
||||
<h2 style={{ margin: 0, fontSize: isMobile ? 18 : 24 }}>角色与组织管理</h2>
|
||||
<h2 style={{ margin: 0, fontSize: isMobile ? 18 : 24 }}>
|
||||
<TeamOutlined style={{ marginRight: 8 }} />
|
||||
角色与组织管理
|
||||
</h2>
|
||||
<Space wrap>
|
||||
<Button
|
||||
type="primary"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Card, Table, Tag, Button, Space, message, Modal, Form, Select, InputNumber, Input, Descriptions } from 'antd';
|
||||
import { PlusOutlined, TeamOutlined, UserOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { Card, Table, Tag, Button, Space, message, Modal, Form, Select, InputNumber, Input, Descriptions, Drawer } from 'antd';
|
||||
import { PlusOutlined, UserOutlined, EditOutlined, DeleteOutlined, UnorderedListOutlined, BankOutlined } from '@ant-design/icons';
|
||||
import { useStore } from '../store';
|
||||
import { useCharacterSync } from '../store/hooks';
|
||||
import axios from 'axios';
|
||||
@@ -57,6 +57,7 @@ export default function Organizations() {
|
||||
const [editOrgForm] = Form.useForm();
|
||||
const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
|
||||
const [modal, contextHolder] = Modal.useModal();
|
||||
const [orgListVisible, setOrgListVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
@@ -82,7 +83,7 @@ export default function Organizations() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [projectId, selectedOrg]);
|
||||
}, [projectId]);
|
||||
|
||||
const loadCharacters = useCallback(async () => {
|
||||
try {
|
||||
@@ -300,61 +301,169 @@ export default function Organizations() {
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
{contextHolder}
|
||||
<Card
|
||||
title={
|
||||
<Space wrap>
|
||||
<TeamOutlined />
|
||||
<span style={{ fontSize: isMobile ? 14 : 16 }}>组织管理</span>
|
||||
{!isMobile && <Tag color="blue">{currentProject?.title}</Tag>}
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
|
||||
{/* 页面标题 - 仅桌面端显示 */}
|
||||
{!isMobile && (
|
||||
<div style={{
|
||||
display: isMobile ? 'flex' : 'grid',
|
||||
flexDirection: isMobile ? 'column' : undefined,
|
||||
gridTemplateColumns: isMobile ? undefined : '300px 1fr',
|
||||
gap: isMobile ? '16px' : '24px',
|
||||
maxHeight: isMobile ? 'calc(100vh - 200px)' : undefined,
|
||||
overflowY: isMobile ? 'auto' : undefined
|
||||
padding: '16px 0',
|
||||
marginBottom: 16,
|
||||
borderBottom: '1px solid #f0f0f0'
|
||||
}}>
|
||||
{/* 左侧:组织列表 */}
|
||||
<div>
|
||||
<Card
|
||||
size="small"
|
||||
title={`组织列表 (${organizations.length})`}
|
||||
loading={loading}
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
{organizations.map(org => (
|
||||
<Card
|
||||
key={org.id}
|
||||
size="small"
|
||||
hoverable
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
border: selectedOrg?.id === org.id ? '2px solid var(--color-primary)' : '1px solid var(--color-border-secondary)'
|
||||
}}
|
||||
onClick={() => handleSelectOrganization(org)}
|
||||
>
|
||||
<Space direction="vertical" size="small" style={{ width: '100%' }}>
|
||||
<strong>{org.name}</strong>
|
||||
<Tag>{org.type}</Tag>
|
||||
<div style={{ fontSize: '12px', color: '#666' }}>
|
||||
成员: {org.member_count} | 势力: {org.power_level}
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
))}
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
<h2 style={{ margin: 0, fontSize: 24 }}>
|
||||
<BankOutlined style={{ marginRight: 8 }} />
|
||||
组织管理
|
||||
</h2>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
gap: isMobile ? 0 : 16,
|
||||
flexDirection: isMobile ? 'column' : 'row',
|
||||
overflow: 'hidden'
|
||||
}}>
|
||||
{/* 左侧组织列表 - 桌面端 */}
|
||||
{!isMobile && (
|
||||
<Card
|
||||
title={`组织列表 (${organizations.length})`}
|
||||
style={{ width: 300, height: '100%', overflow: 'hidden' }}
|
||||
bodyStyle={{ padding: 0, height: 'calc(100% - 57px)', overflow: 'auto' }}
|
||||
loading={loading}
|
||||
>
|
||||
{organizations.length === 0 ? (
|
||||
<div style={{ textAlign: 'center', padding: '40px 20px', color: '#999' }}>
|
||||
暂无组织
|
||||
</div>
|
||||
) : (
|
||||
<Space direction="vertical" style={{ width: '100%', padding: '12px' }}>
|
||||
{organizations.map(org => (
|
||||
<Card
|
||||
key={org.id}
|
||||
size="small"
|
||||
hoverable
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
border: selectedOrg?.id === org.id ? '2px solid #1890ff' : '1px solid #d9d9d9',
|
||||
background: selectedOrg?.id === org.id ? '#e6f7ff' : 'transparent'
|
||||
}}
|
||||
onClick={() => handleSelectOrganization(org)}
|
||||
>
|
||||
<Space direction="vertical" size="small" style={{ width: '100%' }}>
|
||||
<strong style={{ fontSize: 14 }}>{org.name}</strong>
|
||||
<Tag color="blue">{org.type}</Tag>
|
||||
<div style={{ fontSize: '12px', color: '#666' }}>
|
||||
成员: {org.member_count} | 势力: {org.power_level}
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
))}
|
||||
</Space>
|
||||
)}
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* 右侧:组织详情和成员 */}
|
||||
<div style={{ minHeight: isMobile ? 'auto' : undefined }}>
|
||||
{selectedOrg ? (
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="large">
|
||||
{/* 移动端组织列表抽屉 */}
|
||||
{isMobile && (
|
||||
<Drawer
|
||||
title="组织列表"
|
||||
placement="left"
|
||||
onClose={() => setOrgListVisible(false)}
|
||||
open={orgListVisible}
|
||||
width="85%"
|
||||
styles={{ body: { padding: 0 } }}
|
||||
>
|
||||
{organizations.length === 0 ? (
|
||||
<div style={{ textAlign: 'center', padding: '40px 20px', color: '#999' }}>
|
||||
暂无组织
|
||||
</div>
|
||||
) : (
|
||||
<Space direction="vertical" style={{ width: '100%', padding: '12px' }}>
|
||||
{organizations.map(org => (
|
||||
<Card
|
||||
key={org.id}
|
||||
size="small"
|
||||
hoverable
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
border: selectedOrg?.id === org.id ? '2px solid #1890ff' : '1px solid #d9d9d9',
|
||||
background: selectedOrg?.id === org.id ? '#e6f7ff' : 'transparent'
|
||||
}}
|
||||
onClick={() => {
|
||||
handleSelectOrganization(org);
|
||||
setOrgListVisible(false);
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical" size="small" style={{ width: '100%' }}>
|
||||
<strong style={{ fontSize: 14 }}>{org.name}</strong>
|
||||
<Tag color="blue">{org.type}</Tag>
|
||||
<div style={{ fontSize: '12px', color: '#666' }}>
|
||||
成员: {org.member_count} | 势力: {org.power_level}
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
))}
|
||||
</Space>
|
||||
)}
|
||||
</Drawer>
|
||||
)}
|
||||
|
||||
{/* 右侧内容区域 */}
|
||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
|
||||
{!selectedOrg ? (
|
||||
<Card style={{ height: '100%' }}>
|
||||
<div style={{ textAlign: 'center', padding: '100px 20px', color: '#999' }}>
|
||||
{isMobile && organizations.length > 0 && (
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<UnorderedListOutlined />}
|
||||
onClick={() => setOrgListVisible(true)}
|
||||
style={{ marginBottom: 20 }}
|
||||
>
|
||||
选择组织
|
||||
</Button>
|
||||
)}
|
||||
<div>请选择一个组织查看详情</div>
|
||||
</div>
|
||||
</Card>
|
||||
) : (
|
||||
<>
|
||||
{/* 工具栏 - 移动端显示项目标题和组织列表按钮 */}
|
||||
{isMobile && (
|
||||
<Card size="small" style={{ marginBottom: 8 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Space>
|
||||
<BankOutlined />
|
||||
<span style={{ fontSize: 14, fontWeight: 600 }}>
|
||||
组织管理
|
||||
</span>
|
||||
<Tag color="blue">{currentProject?.title}</Tag>
|
||||
</Space>
|
||||
<Button
|
||||
icon={<UnorderedListOutlined />}
|
||||
onClick={() => setOrgListVisible(true)}
|
||||
size="small"
|
||||
>
|
||||
列表
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* 内容区域 */}
|
||||
<div style={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
gap: isMobile ? 0 : 16,
|
||||
overflow: 'hidden'
|
||||
}}>
|
||||
<Card
|
||||
style={{ flex: 1, overflow: 'auto' }}
|
||||
bodyStyle={{ padding: isMobile ? '12px' : '24px' }}
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }} size={isMobile ? 'middle' : 'large'}>
|
||||
<Card
|
||||
title="组织详情"
|
||||
size="small"
|
||||
@@ -445,17 +554,13 @@ export default function Organizations() {
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</Space>
|
||||
) : (
|
||||
<Card>
|
||||
<div style={{ textAlign: 'center', padding: '40px', color: '#999' }}>
|
||||
请从左侧选择一个组织查看详情
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* 添加成员模态框 */}
|
||||
<Modal
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Button, List, Modal, Form, Input, message, Empty, Space, Popconfirm, Card, Select, Radio, Tag, InputNumber, Tooltip, Tabs } from 'antd';
|
||||
import { EditOutlined, DeleteOutlined, ThunderboltOutlined, BranchesOutlined, AppstoreAddOutlined, CheckCircleOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import { EditOutlined, DeleteOutlined, ThunderboltOutlined, BranchesOutlined, AppstoreAddOutlined, CheckCircleOutlined, ExclamationCircleOutlined, PlusOutlined, FileTextOutlined } from '@ant-design/icons';
|
||||
import { useStore } from '../store';
|
||||
import { useOutlineSync } from '../store/hooks';
|
||||
import { cardStyles } from '../components/CardStyles';
|
||||
@@ -1904,7 +1904,10 @@ export default function Outline() {
|
||||
alignItems: isMobile ? 'stretch' : 'center'
|
||||
}}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
<h2 style={{ margin: 0, fontSize: isMobile ? 18 : 24 }}>故事大纲</h2>
|
||||
<h2 style={{ margin: 0, fontSize: isMobile ? 18 : 24 }}>
|
||||
<FileTextOutlined style={{ marginRight: 8 }} />
|
||||
故事大纲
|
||||
</h2>
|
||||
{currentProject?.outline_mode && (
|
||||
<Tag color={currentProject.outline_mode === 'one-to-one' ? 'blue' : 'green'} style={{ width: 'fit-content' }}>
|
||||
{currentProject.outline_mode === 'one-to-one' ? '传统模式 (1→1)' : '细化模式 (1→N)'}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Card, Table, Tag, Button, Space, message, Modal, Form, Select, Slider, Input, Tabs, AutoComplete } from 'antd';
|
||||
import { PlusOutlined, TeamOutlined, UserOutlined, EditOutlined } from '@ant-design/icons';
|
||||
import { PlusOutlined, ApartmentOutlined, UserOutlined, EditOutlined } from '@ant-design/icons';
|
||||
import { useStore } from '../store';
|
||||
import axios from 'axios';
|
||||
|
||||
@@ -308,7 +308,7 @@ export default function Relationships() {
|
||||
<Card
|
||||
title={
|
||||
<Space wrap>
|
||||
<TeamOutlined />
|
||||
<ApartmentOutlined />
|
||||
<span style={{ fontSize: isMobile ? 14 : 16 }}>关系管理</span>
|
||||
{!isMobile && <Tag color="blue">{currentProject?.title}</Tag>}
|
||||
</Space>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Card, Descriptions, Empty, Typography, Button, Modal, Form, Input, message, Space } from 'antd';
|
||||
import { Card, Descriptions, Empty, Typography, Button, Modal, Form, Input, message, Flex } from 'antd';
|
||||
import { GlobalOutlined, EditOutlined, SyncOutlined } from '@ant-design/icons';
|
||||
import { useState } from 'react';
|
||||
import { useStore } from '../store';
|
||||
@@ -174,39 +174,51 @@ export default function WorldSetting() {
|
||||
backgroundColor: '#fff',
|
||||
padding: '16px 0',
|
||||
marginBottom: 24,
|
||||
borderBottom: '1px solid #f0f0f0',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between'
|
||||
borderBottom: '1px solid #f0f0f0'
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<GlobalOutlined style={{ fontSize: 24, marginRight: 12, color: 'var(--color-primary)' }} />
|
||||
<h2 style={{ margin: 0 }}>世界设定</h2>
|
||||
</div>
|
||||
<Space>
|
||||
<Button
|
||||
icon={<SyncOutlined />}
|
||||
onClick={handleRegenerate}
|
||||
disabled={isRegenerating}
|
||||
>
|
||||
AI重新生成
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => {
|
||||
editForm.setFieldsValue({
|
||||
world_time_period: currentProject.world_time_period || '',
|
||||
world_location: currentProject.world_location || '',
|
||||
world_atmosphere: currentProject.world_atmosphere || '',
|
||||
world_rules: currentProject.world_rules || '',
|
||||
});
|
||||
setIsEditModalVisible(true);
|
||||
}}
|
||||
>
|
||||
编辑世界观
|
||||
</Button>
|
||||
</Space>
|
||||
<Flex
|
||||
justify="space-between"
|
||||
align="flex-start"
|
||||
gap={12}
|
||||
wrap="wrap"
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', minWidth: 'fit-content' }}>
|
||||
<GlobalOutlined style={{ fontSize: 24, marginRight: 12, color: 'var(--color-primary)' }} />
|
||||
<h2 style={{ margin: 0, whiteSpace: 'nowrap' }}>世界设定</h2>
|
||||
</div>
|
||||
<Flex gap={8} wrap="wrap" style={{ flex: '0 1 auto' }}>
|
||||
<Button
|
||||
icon={<SyncOutlined />}
|
||||
onClick={handleRegenerate}
|
||||
disabled={isRegenerating}
|
||||
style={{
|
||||
minWidth: 'fit-content',
|
||||
flex: '1 1 auto'
|
||||
}}
|
||||
>
|
||||
<span className="button-text-mobile">AI重新生成</span>
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => {
|
||||
editForm.setFieldsValue({
|
||||
world_time_period: currentProject.world_time_period || '',
|
||||
world_location: currentProject.world_location || '',
|
||||
world_atmosphere: currentProject.world_atmosphere || '',
|
||||
world_rules: currentProject.world_rules || '',
|
||||
});
|
||||
setIsEditModalVisible(true);
|
||||
}}
|
||||
style={{
|
||||
minWidth: 'fit-content',
|
||||
flex: '1 1 auto'
|
||||
}}
|
||||
>
|
||||
<span className="button-text-mobile">编辑世界观</span>
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</div>
|
||||
|
||||
{/* 可滚动内容区域 */}
|
||||
|
||||
@@ -180,7 +180,10 @@ export default function WritingStyles() {
|
||||
justifyContent: 'space-between',
|
||||
alignItems: isMobile ? 'stretch' : 'center'
|
||||
}}>
|
||||
<h2 style={{ margin: 0, fontSize: isMobile ? 18 : 24 }}>写作风格管理</h2>
|
||||
<h2 style={{ margin: 0, fontSize: isMobile ? 18 : 24 }}>
|
||||
<EditOutlined style={{ marginRight: 8 }} />
|
||||
写作风格管理
|
||||
</h2>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
|
||||
Reference in New Issue
Block a user