diff --git a/README.md b/README.md index 7bb7c6b..ded1efe 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,17 @@ # legal_counsel +# 系统简介: +# 当前,法律服务存在效率低下、资源分散、普及率不高等问题,缺乏有效的工具来提升学习和工作效率。 +# 为了解决这些问题,我们利用人工智能、大数据等技术,提供一系列智能化法律服务工具, +# 普及法律知识,促进法律知识的学习和研究,帮助公众更好地理解和运用法律,从而推动法律服务行业的现代化和法治社会的建设。 +# 该项目针对的主要用户群体包括法律专业人士、学生、研究人员以及普通公众。 + +# 配置环境: +# VS Code + mySQL + +# 成员: +# 220340238 刘明耀 +# 220340222 张之阳 +# 220340223 开钰昊 +# 210340227 梅诗睿 +# 220340209 钱 浩 diff --git a/doc/行业和领域调研分析报告(模板).docx b/doc/01_智能法律顾问系统_行业和领域调研分析报告.docx similarity index 83% rename from doc/行业和领域调研分析报告(模板).docx rename to doc/01_智能法律顾问系统_行业和领域调研分析报告.docx index 9bd7375..c89fd14 100644 Binary files a/doc/行业和领域调研分析报告(模板).docx and b/doc/01_智能法律顾问系统_行业和领域调研分析报告.docx differ diff --git a/doc/02_软件系统的需求构思及描述-模板2023.docx b/doc/02_智能法律顾问系统_需求构思及描述文档.docx similarity index 100% rename from doc/02_软件系统的需求构思及描述-模板2023.docx rename to doc/02_智能法律顾问系统_需求构思及描述文档.docx diff --git a/doc/03_智能法律顾问系统_需求规格说明书.docx b/doc/03_智能法律顾问系统_需求规格说明书.docx new file mode 100644 index 0000000..58c28aa Binary files /dev/null and b/doc/03_智能法律顾问系统_需求规格说明书.docx differ diff --git a/doc/03_软件需求规格说明书-模板.docx b/doc/03_软件需求规格说明书-模板.docx deleted file mode 100644 index 98e92e3..0000000 Binary files a/doc/03_软件需求规格说明书-模板.docx and /dev/null differ diff --git a/doc/04_软件设计规格说明书-模板.docx b/doc/04_智能法律顾问系统_设计规格说明书.docx similarity index 50% rename from doc/04_软件设计规格说明书-模板.docx rename to doc/04_智能法律顾问系统_设计规格说明书.docx index 5a79101..9386919 100644 Binary files a/doc/04_软件设计规格说明书-模板.docx and b/doc/04_智能法律顾问系统_设计规格说明书.docx differ diff --git a/model/01_智能法律顾问系统_需求模型.docx b/model/01_智能法律顾问系统_需求模型.docx new file mode 100644 index 0000000..dc002d7 Binary files /dev/null and b/model/01_智能法律顾问系统_需求模型.docx differ diff --git a/model/02_智能法律顾问系统_设计模型.docx b/model/02_智能法律顾问系统_设计模型.docx new file mode 100644 index 0000000..5819ee3 Binary files /dev/null and b/model/02_智能法律顾问系统_设计模型.docx differ diff --git a/model/分析类图.png b/model/分析类图.png deleted file mode 100644 index 17cf2b7..0000000 Binary files a/model/分析类图.png and /dev/null differ diff --git a/model/搜索用例顺序图.png b/model/搜索用例顺序图.png deleted file mode 100644 index 63622d2..0000000 Binary files a/model/搜索用例顺序图.png and /dev/null differ diff --git a/model/法律咨询用例顺序图.png b/model/法律咨询用例顺序图.png deleted file mode 100644 index 61b6e36..0000000 Binary files a/model/法律咨询用例顺序图.png and /dev/null differ diff --git a/model/用例图.png b/model/用例图.png deleted file mode 100644 index 00834cd..0000000 Binary files a/model/用例图.png and /dev/null differ diff --git a/model/界面流顺序图.png b/model/界面流顺序图.png deleted file mode 100644 index f81d03d..0000000 Binary files a/model/界面流顺序图.png and /dev/null differ diff --git a/model/软件体系结构设计.png b/model/软件体系结构设计.png deleted file mode 100644 index 12f31f6..0000000 Binary files a/model/软件体系结构设计.png and /dev/null differ diff --git a/other/05_智能法律顾问系统_软件工程课程设计汇报.pptx b/other/05_智能法律顾问系统_软件工程课程设计汇报.pptx new file mode 100644 index 0000000..b7e5ae0 Binary files /dev/null and b/other/05_智能法律顾问系统_软件工程课程设计汇报.pptx differ diff --git a/other/06_智能法律顾问系统_软件开发项目的个人自评报告.xlsx b/other/06_智能法律顾问系统_软件开发项目的个人自评报告.xlsx new file mode 100644 index 0000000..5e58b4a Binary files /dev/null and b/other/06_智能法律顾问系统_软件开发项目的个人自评报告.xlsx differ diff --git a/other/07_智能法律顾问系统_软件开发项目的团队自评报告.xlsx b/other/07_智能法律顾问系统_软件开发项目的团队自评报告.xlsx new file mode 100644 index 0000000..6a0b3f2 Binary files /dev/null and b/other/07_智能法律顾问系统_软件开发项目的团队自评报告.xlsx differ diff --git a/other/08_智能法律顾问系统_220340238刘明耀_实践总结报告.docx b/other/08_智能法律顾问系统_220340238刘明耀_实践总结报告.docx new file mode 100644 index 0000000..c5fd14f Binary files /dev/null and b/other/08_智能法律顾问系统_220340238刘明耀_实践总结报告.docx differ diff --git a/other/09_智能法律顾问系统_演示录屏.mp4 b/other/09_智能法律顾问系统_演示录屏.mp4 new file mode 100644 index 0000000..54d4f81 Binary files /dev/null and b/other/09_智能法律顾问系统_演示录屏.mp4 differ diff --git a/other/10_智能法律顾问系统_宣传海报.png b/other/10_智能法律顾问系统_宣传海报.png new file mode 100644 index 0000000..b19ad6e Binary files /dev/null and b/other/10_智能法律顾问系统_宣传海报.png differ diff --git a/other/11.txt b/other/11.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/智能法律顾问/case-matching.html b/src/智能法律顾问/case-matching.html index 2377504..61160a2 100644 --- a/src/智能法律顾问/case-matching.html +++ b/src/智能法律顾问/case-matching.html @@ -7,6 +7,15 @@ +
+ + + + + + + +

案件匹配

diff --git a/src/智能法律顾问/css/styles0.css b/src/智能法律顾问/css/styles0.css index e81f7d4..e99af04 100644 --- a/src/智能法律顾问/css/styles0.css +++ b/src/智能法律顾问/css/styles0.css @@ -57,11 +57,14 @@ main { text-align: center; width: calc(20% - 20px); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); - transition: transform 0.3s ease; + transition: transform 0.3s ease, box-shadow 0.3s ease; + position: relative; + overflow: hidden; } .feature:hover { transform: translateY(-5px); + box-shadow: 0 6px 12px rgba(255, 255, 255, 0.7); } .feature h2 { @@ -83,6 +86,7 @@ footer { bottom: 0; width: 100%; } + /* 基本重置 */ body, h1, h2, p, a { margin: 0; diff --git a/src/智能法律顾问/css/stylesAdvice.css b/src/智能法律顾问/css/stylesAdvice.css index 345d128..c5cd519 100644 --- a/src/智能法律顾问/css/stylesAdvice.css +++ b/src/智能法律顾问/css/stylesAdvice.css @@ -580,3 +580,600 @@ main { opacity: 1; } } +/* 新增炫光按钮效果 */ +button { + position: relative; + overflow: hidden; + transition: all 0.3s ease; +} + +button::after { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient(45deg, transparent, rgba(255,255,255,0.3), transparent); + transform: rotate(45deg); + animation: shineEffect 3s infinite; +} + +@keyframes shineEffect { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(100%) rotate(45deg); } +} + + +/* 主标题3D效果增强 */ +h1 { + text-shadow: + 2px 2px 0 #b52b27, + 4px 4px 0 rgba(0,0,0,0.2); + transform-style: preserve-3d; + transition: transform 0.3s ease; +} + +h1:hover { + transform: perspective(500px) rotateX(10deg) translateY(-5px); +} + +/* 结果框出现动画优化 */ +.result-box { + transform-origin: top center; + animation: popIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); +} + +@keyframes popIn { + 0% { + transform: scale(0.5) translateY(-100px); + opacity: 0; + } + 70% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +/* 页面滚动渐变效果 */ +main { + position: relative; + background: linear-gradient( + 135deg, + rgba(255,255,255,0.1), + rgba(255,255,255,0.05) + ); + backdrop-filter: blur(10px); + border: 1px solid rgba(255,255,255,0.1); + animation: mainGlow 4s infinite alternate; +} + +/* 磁性按钮效果 */ +button { + position: relative; + transition: transform 0.2s; +} + +button:hover { + --magnetic-offset: 0px; + transform: translate( + calc(var(--magnetic-x, 0) * var(--magnetic-offset, 0)), + calc(var(--magnetic-y, 0) * var(--magnetic-offset, 0)) + ); +} + +/* 液态背景效果 */ +.liquid-bg { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, #d9534f, #fe5b56); + filter: url('#liquid'); + opacity: 0.1; + z-index: -1; + animation: liquidMove 20s ease-in-out infinite; +} + +@keyframes liquidMove { + 0%, 100% { transform: scale(1) rotate(0deg); } + 50% { transform: scale(1.1) rotate(3deg); } +} + + + +/* 输入框波纹效果 */ +input[type="text"] { + position: relative; + overflow: hidden; +} + +input[type="text"]::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 300px; + background: radial-gradient(circle, rgba(217, 83, 79, 0.2) 0%, transparent 70%); + transform: translate(-50%, -50%) scale(0); + animation: rippleEffect 2s linear infinite; +} + +@keyframes rippleEffect { + 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; } + 100% { transform: translate(-50%, -50%) scale(1); opacity: 0; } +} + +/* 3D卡片翻转效果 */ +.result-box { + transform-style: preserve-3d; + transition: transform 0.8s; +} + +.result-box:hover { + transform: rotateY(10deg) rotateX(5deg); +} + +/* 动态粒子连线效果 */ +.particle-connect { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; +} + +.particle-dot { + position: absolute; + width: 3px; + height: 3px; + background: rgba(217, 83, 79, 0.3); + border-radius: 50%; +} + +/* 滚动视差效果 */ +main { + transform-style: preserve-3d; + perspective: 1000px; +} + +main > * { + transform: translateZ(var(--depth, 0)); + transition: transform 0.3s; +} + + + +/* 动态渐变边框 */ +.gradient-border { + position: relative; + border: none; +} + +.gradient-border::before { + content: ''; + position: absolute; + inset: -2px; + background: linear-gradient(45deg, #d9534f, #fe5b56, #d9534f); + background-size: 200% 200%; + animation: borderGradient 3s linear infinite; + z-index: -1; + border-radius: inherit; +} + +@keyframes borderGradient { + 0% { background-position: 0% 0%; } + 100% { background-position: 200% 200%; } +} + + +/* 页脚样式优化 */ +footer { + background: transparent; + border-top: 1px solid rgba(255, 255, 255, 0.1); + padding: 20px 0; +} + +/* 平滑滚动 */ +html { + scroll-behavior: smooth; +} + +/* 选中文本样式 */ +::selection { + background: rgba(217, 83, 79, 0.3); + color: #fff; +} + +/* ... existing code ... */ + +/* 高级玻璃拟态效果 */ +.glass-morphism { + background: rgba(217, 83, 79, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: + 0 8px 32px rgba(217, 83, 79, 0.1), + inset 0 0 0 1px rgba(255, 255, 255, 0.05); +} + +/* 智能悬停效果 */ +.smart-hover { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + transform-origin: center; +} + +.smart-hover:hover { + transform: translateY(-2px) scale(1.02); + box-shadow: + 0 10px 20px rgba(217, 83, 79, 0.2), + 0 6px 6px rgba(217, 83, 79, 0.1); +} + +/* 高级按钮动画 */ +.advanced-button { + position: relative; + isolation: isolate; + overflow: hidden; +} + +.advanced-button::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 45deg, + transparent, + rgba(255, 255, 255, 0.2), + transparent + ); + transform: translateX(-100%) rotate(45deg); + transition: transform 0.6s; +} + +.advanced-button:hover::before { + transform: translateX(100%) rotate(45deg); +} + +/* 动态边框效果 */ +.dynamic-border { + --border-width: 2px; + --border-radius: 5px; + position: relative; + border-radius: var(--border-radius); +} + +.dynamic-border::before { + content: ''; + position: absolute; + inset: calc(-1 * var(--border-width)); + background: linear-gradient( + 90deg, + #d9534f, + #fe5b56, + #d9534f + ); + border-radius: calc(var(--border-radius) + var(--border-width)); + animation: borderRotate 3s linear infinite; + z-index: -1; +} + +@keyframes borderRotate { + 0% { filter: hue-rotate(0deg); } + 100% { filter: hue-rotate(360deg); } +} + +/* 高级文本渐变效果 */ +.gradient-text { + background: linear-gradient( + 135deg, + #d9534f, + #fe5b56, + #d9534f + ); + background-size: 200% 200%; + animation: gradientMove 3s ease infinite; + -webkit-text-fill-color: transparent; +} + +@keyframes gradientMove { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} + +/* 高级加载动画 */ +.loading-advanced { + width: 40px; + height: 40px; + position: relative; +} + +.loading-advanced::before, +.loading-advanced::after { + content: ''; + position: absolute; + inset: 0; + border-radius: 50%; + border: 3px solid transparent; + animation: loadingRotate 1.5s linear infinite; +} + +.loading-advanced::before { + border-top-color: #d9534f; + animation-delay: 0.75s; +} + +.loading-advanced::after { + border-bottom-color: #fe5b56; +} + +@keyframes loadingRotate { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 高级滚动条样式 */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: rgba(217, 83, 79, 0.1); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: rgba(217, 83, 79, 0.5); + border-radius: 4px; + transition: background 0.3s; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(217, 83, 79, 0.8); +} + +/* 高级输入框效果 */ +.input-advanced { + border: none; + border-bottom: 2px solid rgba(217, 83, 79, 0.3); + background: transparent; + transition: all 0.3s; +} + +.input-advanced:focus { + border-bottom-color: #d9534f; + box-shadow: 0 4px 6px -4px rgba(217, 83, 79, 0.5); + outline: none; +} + +/* 高级卡片效果 */ +.card-advanced { + position: relative; + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(10px); + border-radius: 10px; + transition: all 0.3s; +} + +.card-advanced::before { + content: ''; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1px; + background: linear-gradient(135deg, #d9534f, #fe5b56); + mask: linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; +} + + + +/* 高级3D深度效果 */ +.depth-effect { + transform-style: preserve-3d; + perspective: 1000px; +} + +.depth-layer { + transform: translateZ(var(--depth)); + will-change: transform; +} + +/* 高级霓虹发光效果 */ +.neon-glow { + --glow-color: #d9534f; + box-shadow: + 0 0 5px var(--glow-color), + 0 0 10px var(--glow-color), + 0 0 20px var(--glow-color), + 0 0 40px var(--glow-color); + animation: neonPulse 2s infinite; +} + +@keyframes neonPulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.7; } +} + +/* 高级液态背景 */ +.liquid-background { + background: linear-gradient(45deg, #d9534f, #fe5b56); + filter: url('#liquid-filter'); + animation: liquidFlow 10s infinite; +} + + + +/* 高级磁性悬停效果 */ +.magnetic-hover { + --magnetic-x: 0; + --magnetic-y: 0; + transform: translate( + calc(var(--magnetic-x) * 1px), + calc(var(--magnetic-y) * 1px) + ); + transition: transform 0.2s cubic-bezier(0.33, 1, 0.68, 1); +} + +/* 高级粒子系统 */ +.particle-system { + position: relative; + overflow: hidden; +} + +.particle { + position: absolute; + pointer-events: none; + background: radial-gradient(circle, #d9534f 0%, transparent 70%); + border-radius: 50%; + animation: particleFloat 4s infinite; +} + +@keyframes particleFloat { + 0% { transform: translate(0, 0) rotate(0deg); } + 100% { transform: translate(var(--x), var(--y)) rotate(360deg); } +} + +/* 高级形态变换效果 */ +.morphing-shape { + clip-path: var(--clip-path); + transition: clip-path 0.6s cubic-bezier(0.4, 0, 0.2, 1); + animation: morphing 10s infinite; +} + +@keyframes morphing { + 0% { --clip-path: circle(50% at 50% 50%); } + 25% { --clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); } + 50% { --clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); } + 75% { --clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); } + 100% { --clip-path: circle(50% at 50% 50%); } +} + +/* 高级光线追踪效果 */ +.ray-tracing { + position: relative; + overflow: hidden; +} + +.ray { + position: absolute; + width: 1px; + height: 100%; + background: linear-gradient(to bottom, transparent, rgba(217, 83, 79, 0.5), transparent); + animation: rayMove 2s linear infinite; + transform-origin: 50% 0%; +} + +@keyframes rayMove { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(200%) rotate(45deg); } +} + +/* 高级全息效果 */ +.holographic { + background: linear-gradient( + 135deg, + rgba(217, 83, 79, 0.2), + rgba(254, 91, 86, 0.2) + ); + position: relative; +} + +.holographic::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 45deg, + transparent 0%, + rgba(255, 255, 255, 0.4) 45%, + rgba(255, 255, 255, 0.7) 50%, + rgba(255, 255, 255, 0.4) 55%, + transparent 100% + ); + transform: translateX(-100%); + animation: holographicShine 3s infinite; +} + +@keyframes holographicShine { + 0% { transform: translateX(-100%) rotate(0deg); } + 100% { transform: translateX(100%) rotate(0deg); } +} + +/* 高级波浪效果 */ +.wave-effect { + position: relative; + overflow: hidden; +} + +.wave { + position: absolute; + width: 200%; + height: 200%; + top: -50%; + left: -50%; + background: radial-gradient(circle at center, rgba(217, 83, 79, 0.2) 0%, transparent 70%); + animation: waveRotate 10s linear infinite; +} + +@keyframes waveRotate { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 高级模糊分层效果 */ +.blur-layers { + position: relative; +} + +.blur-layer { + position: absolute; + inset: 0; + backdrop-filter: blur(var(--blur-amount)); + opacity: var(--layer-opacity); + transform: translateZ(var(--layer-depth)) scale(var(--layer-scale)); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* 高级交互反馈 */ +.interaction-feedback { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.interaction-feedback:active { + transform: scale(0.95); + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.2); +} + +/* 高级文字效果 */ +.advanced-text { + background: linear-gradient( + 45deg, + #d9534f, + #fe5b56, + #d9534f + ); + background-size: 200% auto; + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + animation: textGradient 3s linear infinite; + text-shadow: + 3px 3px 6px rgba(0, 0, 0, 0.2), + 0 0 10px rgba(217, 83, 79, 0.5); +} + +@keyframes textGradient { + to { background-position: 200% center; } +} \ No newline at end of file diff --git a/src/智能法律顾问/css/stylesCase.css b/src/智能法律顾问/css/stylesCase.css index 015a74a..8a03a9b 100644 --- a/src/智能法律顾问/css/stylesCase.css +++ b/src/智能法律顾问/css/stylesCase.css @@ -576,3 +576,604 @@ main { opacity: 1; } } + + +/*新增*/ + +/* 新增炫光按钮效果 */ +button { + position: relative; + overflow: hidden; + transition: all 0.3s ease; +} + +button::after { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient(45deg, transparent, rgba(255,255,255,0.3), transparent); + transform: rotate(45deg); + animation: shineEffect 3s infinite; +} + +@keyframes shineEffect { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(100%) rotate(45deg); } +} + + +/* 主标题3D效果增强 */ +h1 { + text-shadow: + 2px 2px 0 #b52b27, + 4px 4px 0 rgba(0,0,0,0.2); + transform-style: preserve-3d; + transition: transform 0.3s ease; +} + +h1:hover { + transform: perspective(500px) rotateX(10deg) translateY(-5px); +} + +/* 结果框出现动画优化 */ +.result-box { + transform-origin: top center; + animation: popIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); +} + +@keyframes popIn { + 0% { + transform: scale(0.5) translateY(-100px); + opacity: 0; + } + 70% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +/* 页面滚动渐变效果 */ +main { + position: relative; + background: linear-gradient( + 135deg, + rgba(255,255,255,0.1), + rgba(255,255,255,0.05) + ); + backdrop-filter: blur(10px); + border: 1px solid rgba(255,255,255,0.1); + animation: mainGlow 4s infinite alternate; +} + +/* 磁性按钮效果 */ +button { + position: relative; + transition: transform 0.2s; +} + +button:hover { + --magnetic-offset: 0px; + transform: translate( + calc(var(--magnetic-x, 0) * var(--magnetic-offset, 0)), + calc(var(--magnetic-y, 0) * var(--magnetic-offset, 0)) + ); +} + +/* 液态背景效果 */ +.liquid-bg { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, #d9534f, #fe5b56); + filter: url('#liquid'); + opacity: 0.1; + z-index: -1; + animation: liquidMove 20s ease-in-out infinite; +} + +@keyframes liquidMove { + 0%, 100% { transform: scale(1) rotate(0deg); } + 50% { transform: scale(1.1) rotate(3deg); } +} + + + +/* 输入框波纹效果 */ +input[type="text"] { + position: relative; + overflow: hidden; +} + +input[type="text"]::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 300px; + background: radial-gradient(circle, rgba(217, 83, 79, 0.2) 0%, transparent 70%); + transform: translate(-50%, -50%) scale(0); + animation: rippleEffect 2s linear infinite; +} + +@keyframes rippleEffect { + 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; } + 100% { transform: translate(-50%, -50%) scale(1); opacity: 0; } +} + +/* 3D卡片翻转效果 */ +.result-box { + transform-style: preserve-3d; + transition: transform 0.8s; +} + +.result-box:hover { + transform: rotateY(10deg) rotateX(5deg); +} + +/* 动态粒子连线效果 */ +.particle-connect { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; +} + +.particle-dot { + position: absolute; + width: 3px; + height: 3px; + background: rgba(217, 83, 79, 0.3); + border-radius: 50%; +} + +/* 滚动视差效果 */ +main { + transform-style: preserve-3d; + perspective: 1000px; +} + +main > * { + transform: translateZ(var(--depth, 0)); + transition: transform 0.3s; +} + + + +/* 动态渐变边框 */ +.gradient-border { + position: relative; + border: none; +} + +.gradient-border::before { + content: ''; + position: absolute; + inset: -2px; + background: linear-gradient(45deg, #d9534f, #fe5b56, #d9534f); + background-size: 200% 200%; + animation: borderGradient 3s linear infinite; + z-index: -1; + border-radius: inherit; +} + +@keyframes borderGradient { + 0% { background-position: 0% 0%; } + 100% { background-position: 200% 200%; } +} + + +/* 页脚样式优化 */ +footer { + background: transparent; + border-top: 1px solid rgba(255, 255, 255, 0.1); + padding: 20px 0; +} + +/* 平滑滚动 */ +html { + scroll-behavior: smooth; +} + +/* 选中文本样式 */ +::selection { + background: rgba(217, 83, 79, 0.3); + color: #fff; +} + +/* ... existing code ... */ + +/* 高级玻璃拟态效果 */ +.glass-morphism { + background: rgba(217, 83, 79, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: + 0 8px 32px rgba(217, 83, 79, 0.1), + inset 0 0 0 1px rgba(255, 255, 255, 0.05); +} + +/* 智能悬停效果 */ +.smart-hover { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + transform-origin: center; +} + +.smart-hover:hover { + transform: translateY(-2px) scale(1.02); + box-shadow: + 0 10px 20px rgba(217, 83, 79, 0.2), + 0 6px 6px rgba(217, 83, 79, 0.1); +} + +/* 高级按钮动画 */ +.advanced-button { + position: relative; + isolation: isolate; + overflow: hidden; +} + +.advanced-button::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 45deg, + transparent, + rgba(255, 255, 255, 0.2), + transparent + ); + transform: translateX(-100%) rotate(45deg); + transition: transform 0.6s; +} + +.advanced-button:hover::before { + transform: translateX(100%) rotate(45deg); +} + +/* 动态边框效果 */ +.dynamic-border { + --border-width: 2px; + --border-radius: 5px; + position: relative; + border-radius: var(--border-radius); +} + +.dynamic-border::before { + content: ''; + position: absolute; + inset: calc(-1 * var(--border-width)); + background: linear-gradient( + 90deg, + #d9534f, + #fe5b56, + #d9534f + ); + border-radius: calc(var(--border-radius) + var(--border-width)); + animation: borderRotate 3s linear infinite; + z-index: -1; +} + +@keyframes borderRotate { + 0% { filter: hue-rotate(0deg); } + 100% { filter: hue-rotate(360deg); } +} + +/* 高级文本渐变效果 */ +.gradient-text { + background: linear-gradient( + 135deg, + #d9534f, + #fe5b56, + #d9534f + ); + background-size: 200% 200%; + animation: gradientMove 3s ease infinite; + -webkit-text-fill-color: transparent; +} + +@keyframes gradientMove { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} + +/* 高级加载动画 */ +.loading-advanced { + width: 40px; + height: 40px; + position: relative; +} + +.loading-advanced::before, +.loading-advanced::after { + content: ''; + position: absolute; + inset: 0; + border-radius: 50%; + border: 3px solid transparent; + animation: loadingRotate 1.5s linear infinite; +} + +.loading-advanced::before { + border-top-color: #d9534f; + animation-delay: 0.75s; +} + +.loading-advanced::after { + border-bottom-color: #fe5b56; +} + +@keyframes loadingRotate { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 高级滚动条样式 */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: rgba(217, 83, 79, 0.1); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: rgba(217, 83, 79, 0.5); + border-radius: 4px; + transition: background 0.3s; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(217, 83, 79, 0.8); +} + +/* 高级输入框效果 */ +.input-advanced { + border: none; + border-bottom: 2px solid rgba(217, 83, 79, 0.3); + background: transparent; + transition: all 0.3s; +} + +.input-advanced:focus { + border-bottom-color: #d9534f; + box-shadow: 0 4px 6px -4px rgba(217, 83, 79, 0.5); + outline: none; +} + +/* 高级卡片效果 */ +.card-advanced { + position: relative; + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(10px); + border-radius: 10px; + transition: all 0.3s; +} + +.card-advanced::before { + content: ''; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1px; + background: linear-gradient(135deg, #d9534f, #fe5b56); + mask: linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; +} + + + +/* 高级3D深度效果 */ +.depth-effect { + transform-style: preserve-3d; + perspective: 1000px; +} + +.depth-layer { + transform: translateZ(var(--depth)); + will-change: transform; +} + +/* 高级霓虹发光效果 */ +.neon-glow { + --glow-color: #d9534f; + box-shadow: + 0 0 5px var(--glow-color), + 0 0 10px var(--glow-color), + 0 0 20px var(--glow-color), + 0 0 40px var(--glow-color); + animation: neonPulse 2s infinite; +} + +@keyframes neonPulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.7; } +} + +/* 高级液态背景 */ +.liquid-background { + background: linear-gradient(45deg, #d9534f, #fe5b56); + filter: url('#liquid-filter'); + animation: liquidFlow 10s infinite; +} + + + +/* 高级磁性悬停效果 */ +.magnetic-hover { + --magnetic-x: 0; + --magnetic-y: 0; + transform: translate( + calc(var(--magnetic-x) * 1px), + calc(var(--magnetic-y) * 1px) + ); + transition: transform 0.2s cubic-bezier(0.33, 1, 0.68, 1); +} + +/* 高级粒子系统 */ +.particle-system { + position: relative; + overflow: hidden; +} + +.particle { + position: absolute; + pointer-events: none; + background: radial-gradient(circle, #d9534f 0%, transparent 70%); + border-radius: 50%; + animation: particleFloat 4s infinite; +} + +@keyframes particleFloat { + 0% { transform: translate(0, 0) rotate(0deg); } + 100% { transform: translate(var(--x), var(--y)) rotate(360deg); } +} + +/* 高级形态变换效果 */ +.morphing-shape { + clip-path: var(--clip-path); + transition: clip-path 0.6s cubic-bezier(0.4, 0, 0.2, 1); + animation: morphing 10s infinite; +} + +@keyframes morphing { + 0% { --clip-path: circle(50% at 50% 50%); } + 25% { --clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); } + 50% { --clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); } + 75% { --clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); } + 100% { --clip-path: circle(50% at 50% 50%); } +} + +/* 高级光线追踪效果 */ +.ray-tracing { + position: relative; + overflow: hidden; +} + +.ray { + position: absolute; + width: 1px; + height: 100%; + background: linear-gradient(to bottom, transparent, rgba(217, 83, 79, 0.5), transparent); + animation: rayMove 2s linear infinite; + transform-origin: 50% 0%; +} + +@keyframes rayMove { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(200%) rotate(45deg); } +} + +/* 高级全息效果 */ +.holographic { + background: linear-gradient( + 135deg, + rgba(217, 83, 79, 0.2), + rgba(254, 91, 86, 0.2) + ); + position: relative; +} + +.holographic::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 45deg, + transparent 0%, + rgba(255, 255, 255, 0.4) 45%, + rgba(255, 255, 255, 0.7) 50%, + rgba(255, 255, 255, 0.4) 55%, + transparent 100% + ); + transform: translateX(-100%); + animation: holographicShine 3s infinite; +} + +@keyframes holographicShine { + 0% { transform: translateX(-100%) rotate(0deg); } + 100% { transform: translateX(100%) rotate(0deg); } +} + +/* 高级波浪效果 */ +.wave-effect { + position: relative; + overflow: hidden; +} + +.wave { + position: absolute; + width: 200%; + height: 200%; + top: -50%; + left: -50%; + background: radial-gradient(circle at center, rgba(217, 83, 79, 0.2) 0%, transparent 70%); + animation: waveRotate 10s linear infinite; +} + +@keyframes waveRotate { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 高级模糊分层效果 */ +.blur-layers { + position: relative; +} + +.blur-layer { + position: absolute; + inset: 0; + backdrop-filter: blur(var(--blur-amount)); + opacity: var(--layer-opacity); + transform: translateZ(var(--layer-depth)) scale(var(--layer-scale)); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* 高级交互反馈 */ +.interaction-feedback { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.interaction-feedback:active { + transform: scale(0.95); + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.2); +} + +/* 高级文字效果 */ +.advanced-text { + background: linear-gradient( + 45deg, + #d9534f, + #fe5b56, + #d9534f + ); + background-size: 200% auto; + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + animation: textGradient 3s linear infinite; + text-shadow: + 3px 3px 6px rgba(0, 0, 0, 0.2), + 0 0 10px rgba(217, 83, 79, 0.5); +} + +@keyframes textGradient { + to { background-position: 200% center; } +} \ No newline at end of file diff --git a/src/智能法律顾问/css/stylesLearn.css b/src/智能法律顾问/css/stylesLearn.css index d62b981..161bc30 100644 --- a/src/智能法律顾问/css/stylesLearn.css +++ b/src/智能法律顾问/css/stylesLearn.css @@ -565,4 +565,287 @@ main { box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); animation-fill-mode: forwards; /* 保持动画结束状态 */ overflow: hidden; /* 隐藏内容超出部分 */ +} + +/* 新增炫光按钮效果 */ +button { + position: relative; + overflow: hidden; + transition: all 0.3s ease; +} + +button::after { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient(45deg, transparent, rgba(255,255,255,0.3), transparent); + transform: rotate(45deg); + animation: shineEffect 3s infinite; +} + +@keyframes shineEffect { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(100%) rotate(45deg); } +} + + +/* 主标题3D效果增强 */ +h1 { + text-shadow: + 2px 2px 0 #b52b27, + 4px 4px 0 rgba(0,0,0,0.2); + transform-style: preserve-3d; + transition: transform 0.3s ease; +} + +h1:hover { + transform: perspective(500px) rotateX(10deg) translateY(-5px); +} + +/* 结果框出现动画优化 */ +.result-box { + transform-origin: top center; + animation: popIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); +} + +@keyframes popIn { + 0% { + transform: scale(0.5) translateY(-100px); + opacity: 0; + } + 70% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +/* 页面滚动渐变效果 */ +main { + position: relative; + background: linear-gradient( + 135deg, + rgba(255,255,255,0.1), + rgba(255,255,255,0.05) + ); + backdrop-filter: blur(10px); + border: 1px solid rgba(255,255,255,0.1); + animation: mainGlow 4s infinite alternate; +} + +/* 新增炫光按钮效果 */ +button { + position: relative; + overflow: hidden; + transition: all 0.3s ease; +} + +button::after { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient(45deg, transparent, rgba(255,255,255,0.3), transparent); + transform: rotate(45deg); + animation: shineEffect 3s infinite; +} + +@keyframes shineEffect { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(100%) rotate(45deg); } +} + + +/* 主标题3D效果增强 */ +h1 { + text-shadow: + 2px 2px 0 #b52b27, + 4px 4px 0 rgba(0,0,0,0.2); + transform-style: preserve-3d; + transition: transform 0.3s ease; +} + +h1:hover { + transform: perspective(500px) rotateX(10deg) translateY(-5px); +} + +/* 结果框出现动画优化 */ +.result-box { + transform-origin: top center; + animation: popIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); +} + +@keyframes popIn { + 0% { + transform: scale(0.5) translateY(-100px); + opacity: 0; + } + 70% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +/* 页面滚动渐变效果 */ +main { + position: relative; + background: linear-gradient( + 135deg, + rgba(255,255,255,0.1), + rgba(255,255,255,0.05) + ); + backdrop-filter: blur(10px); + border: 1px solid rgba(255,255,255,0.1); + animation: mainGlow 4s infinite alternate; +} + +/* 磁性按钮效果 */ +button { + position: relative; + transition: transform 0.2s; +} + +button:hover { + --magnetic-offset: 0px; + transform: translate( + calc(var(--magnetic-x, 0) * var(--magnetic-offset, 0)), + calc(var(--magnetic-y, 0) * var(--magnetic-offset, 0)) + ); +} + +/* 液态背景效果 */ +.liquid-bg { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, #d9534f, #fe5b56); + filter: url('#liquid'); + opacity: 0.1; + z-index: -1; + animation: liquidMove 20s ease-in-out infinite; +} + +@keyframes liquidMove { + 0%, 100% { transform: scale(1) rotate(0deg); } + 50% { transform: scale(1.1) rotate(3deg); } +} + + + +/* 输入框波纹效果 */ +input[type="text"] { + position: relative; + overflow: hidden; +} + +input[type="text"]::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 300px; + background: radial-gradient(circle, rgba(217, 83, 79, 0.2) 0%, transparent 70%); + transform: translate(-50%, -50%) scale(0); + animation: rippleEffect 2s linear infinite; +} + +@keyframes rippleEffect { + 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; } + 100% { transform: translate(-50%, -50%) scale(1); opacity: 0; } +} + +/* 3D卡片翻转效果 */ +.result-box { + transform-style: preserve-3d; + transition: transform 0.8s; +} + +.result-box:hover { + transform: rotateY(10deg) rotateX(5deg); +} + +/* 动态粒子连线效果 */ +.particle-connect { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; +} + +.particle-dot { + position: absolute; + width: 3px; + height: 3px; + background: rgba(217, 83, 79, 0.3); + border-radius: 50%; +} + +/* 滚动视差效果 */ +main { + transform-style: preserve-3d; + perspective: 1000px; +} + +main > * { + transform: translateZ(var(--depth, 0)); + transition: transform 0.3s; +} + + + +/* 动态渐变边框 */ +.gradient-border { + position: relative; + border: none; +} + +.gradient-border::before { + content: ''; + position: absolute; + inset: -2px; + background: linear-gradient(45deg, #d9534f, #fe5b56, #d9534f); + background-size: 200% 200%; + animation: borderGradient 3s linear infinite; + z-index: -1; + border-radius: inherit; +} + +@keyframes borderGradient { + 0% { background-position: 0% 0%; } + 100% { background-position: 200% 200%; } +} + + +/* 页脚样式优化 */ +footer { + background: transparent; + border-top: 1px solid rgba(255, 255, 255, 0.1); + padding: 20px 0; +} + +/* 平滑滚动 */ +html { + scroll-behavior: smooth; +} + +/* 选中文本样式 */ +::selection { + background: rgba(217, 83, 79, 0.3); + color: #fff; } \ No newline at end of file diff --git a/src/智能法律顾问/css/stylesNews.css b/src/智能法律顾问/css/stylesNews.css index d62b981..44c7851 100644 --- a/src/智能法律顾问/css/stylesNews.css +++ b/src/智能法律顾问/css/stylesNews.css @@ -565,4 +565,602 @@ main { box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); animation-fill-mode: forwards; /* 保持动画结束状态 */ overflow: hidden; /* 隐藏内容超出部分 */ +} + +/* 新增炫光按钮效果 */ +button { + position: relative; + overflow: hidden; + transition: all 0.3s ease; +} + +button::after { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient(45deg, transparent, rgba(255,255,255,0.3), transparent); + transform: rotate(45deg); + animation: shineEffect 3s infinite; +} + +@keyframes shineEffect { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(100%) rotate(45deg); } +} + + +/* 主标题3D效果增强 */ +h1 { + text-shadow: + 2px 2px 0 #b52b27, + 4px 4px 0 rgba(0,0,0,0.2); + transform-style: preserve-3d; + transition: transform 0.3s ease; +} + +h1:hover { + transform: perspective(500px) rotateX(10deg) translateY(-5px); +} + +/* 结果框出现动画优化 */ +.result-box { + transform-origin: top center; + animation: popIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); +} + +@keyframes popIn { + 0% { + transform: scale(0.5) translateY(-100px); + opacity: 0; + } + 70% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +/* 页面滚动渐变效果 */ +main { + position: relative; + background: linear-gradient( + 135deg, + rgba(255,255,255,0.1), + rgba(255,255,255,0.05) + ); + backdrop-filter: blur(10px); + border: 1px solid rgba(255,255,255,0.1); + animation: mainGlow 4s infinite alternate; +} + +/* 磁性按钮效果 */ +button { + position: relative; + transition: transform 0.2s; +} + +button:hover { + --magnetic-offset: 0px; + transform: translate( + calc(var(--magnetic-x, 0) * var(--magnetic-offset, 0)), + calc(var(--magnetic-y, 0) * var(--magnetic-offset, 0)) + ); +} + +/* 液态背景效果 */ +.liquid-bg { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, #d9534f, #fe5b56); + filter: url('#liquid'); + opacity: 0.1; + z-index: -1; + animation: liquidMove 20s ease-in-out infinite; +} + +@keyframes liquidMove { + 0%, 100% { transform: scale(1) rotate(0deg); } + 50% { transform: scale(1.1) rotate(3deg); } +} + + + +/* 输入框波纹效果 */ +input[type="text"] { + position: relative; + overflow: hidden; +} + +input[type="text"]::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 300px; + background: radial-gradient(circle, rgba(217, 83, 79, 0.2) 0%, transparent 70%); + transform: translate(-50%, -50%) scale(0); + animation: rippleEffect 2s linear infinite; +} + +@keyframes rippleEffect { + 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; } + 100% { transform: translate(-50%, -50%) scale(1); opacity: 0; } +} + +/* 3D卡片翻转效果 */ +.result-box { + transform-style: preserve-3d; + transition: transform 0.8s; +} + +.result-box:hover { + transform: rotateY(10deg) rotateX(5deg); +} + +/* 动态粒子连线效果 */ +.particle-connect { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; +} + +.particle-dot { + position: absolute; + width: 3px; + height: 3px; + background: rgba(217, 83, 79, 0.3); + border-radius: 50%; +} + +/* 滚动视差效果 */ +main { + transform-style: preserve-3d; + perspective: 1000px; +} + +main > * { + transform: translateZ(var(--depth, 0)); + transition: transform 0.3s; +} + + + +/* 动态渐变边框 */ +.gradient-border { + position: relative; + border: none; +} + +.gradient-border::before { + content: ''; + position: absolute; + inset: -2px; + background: linear-gradient(45deg, #d9534f, #fe5b56, #d9534f); + background-size: 200% 200%; + animation: borderGradient 3s linear infinite; + z-index: -1; + border-radius: inherit; +} + +@keyframes borderGradient { + 0% { background-position: 0% 0%; } + 100% { background-position: 200% 200%; } +} + + +/* 页脚样式优化 */ +footer { + background: transparent; + border-top: 1px solid rgba(255, 255, 255, 0.1); + padding: 20px 0; +} + +/* 平滑滚动 */ +html { + scroll-behavior: smooth; +} + +/* 选中文本样式 */ +::selection { + background: rgba(217, 83, 79, 0.3); + color: #fff; +} + +/* ... existing code ... */ + +/* 高级玻璃拟态效果 */ +.glass-morphism { + background: rgba(217, 83, 79, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: + 0 8px 32px rgba(217, 83, 79, 0.1), + inset 0 0 0 1px rgba(255, 255, 255, 0.05); +} + +/* 智能悬停效果 */ +.smart-hover { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + transform-origin: center; +} + +.smart-hover:hover { + transform: translateY(-2px) scale(1.02); + box-shadow: + 0 10px 20px rgba(217, 83, 79, 0.2), + 0 6px 6px rgba(217, 83, 79, 0.1); +} + +/* 高级按钮动画 */ +.advanced-button { + position: relative; + isolation: isolate; + overflow: hidden; +} + +.advanced-button::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 45deg, + transparent, + rgba(255, 255, 255, 0.2), + transparent + ); + transform: translateX(-100%) rotate(45deg); + transition: transform 0.6s; +} + +.advanced-button:hover::before { + transform: translateX(100%) rotate(45deg); +} + +/* 动态边框效果 */ +.dynamic-border { + --border-width: 2px; + --border-radius: 5px; + position: relative; + border-radius: var(--border-radius); +} + +.dynamic-border::before { + content: ''; + position: absolute; + inset: calc(-1 * var(--border-width)); + background: linear-gradient( + 90deg, + #d9534f, + #fe5b56, + #d9534f + ); + border-radius: calc(var(--border-radius) + var(--border-width)); + animation: borderRotate 3s linear infinite; + z-index: -1; +} + +@keyframes borderRotate { + 0% { filter: hue-rotate(0deg); } + 100% { filter: hue-rotate(360deg); } +} + +/* 高级文本渐变效果 */ +.gradient-text { + background: linear-gradient( + 135deg, + #d9534f, + #fe5b56, + #d9534f + ); + background-size: 200% 200%; + animation: gradientMove 3s ease infinite; + -webkit-text-fill-color: transparent; +} + +@keyframes gradientMove { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} + +/* 高级加载动画 */ +.loading-advanced { + width: 40px; + height: 40px; + position: relative; +} + +.loading-advanced::before, +.loading-advanced::after { + content: ''; + position: absolute; + inset: 0; + border-radius: 50%; + border: 3px solid transparent; + animation: loadingRotate 1.5s linear infinite; +} + +.loading-advanced::before { + border-top-color: #d9534f; + animation-delay: 0.75s; +} + +.loading-advanced::after { + border-bottom-color: #fe5b56; +} + +@keyframes loadingRotate { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 高级滚动条样式 */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: rgba(217, 83, 79, 0.1); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: rgba(217, 83, 79, 0.5); + border-radius: 4px; + transition: background 0.3s; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(217, 83, 79, 0.8); +} + +/* 高级输入框效果 */ +.input-advanced { + border: none; + border-bottom: 2px solid rgba(217, 83, 79, 0.3); + background: transparent; + transition: all 0.3s; +} + +.input-advanced:focus { + border-bottom-color: #d9534f; + box-shadow: 0 4px 6px -4px rgba(217, 83, 79, 0.5); + outline: none; +} + +/* 高级卡片效果 */ +.card-advanced { + position: relative; + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(10px); + border-radius: 10px; + transition: all 0.3s; +} + +.card-advanced::before { + content: ''; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1px; + background: linear-gradient(135deg, #d9534f, #fe5b56); + mask: linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; +} + + + +/* 高级3D深度效果 */ +.depth-effect { + transform-style: preserve-3d; + perspective: 1000px; +} + +.depth-layer { + transform: translateZ(var(--depth)); + will-change: transform; +} + +/* 高级霓虹发光效果 */ +.neon-glow { + --glow-color: #d9534f; + box-shadow: + 0 0 5px var(--glow-color), + 0 0 10px var(--glow-color), + 0 0 20px var(--glow-color), + 0 0 40px var(--glow-color); + animation: neonPulse 2s infinite; +} + +@keyframes neonPulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.7; } +} + +/* 高级液态背景 */ +.liquid-background { + background: linear-gradient(45deg, #d9534f, #fe5b56); + filter: url('#liquid-filter'); + animation: liquidFlow 10s infinite; +} + + + +/* 高级磁性悬停效果 */ +.magnetic-hover { + --magnetic-x: 0; + --magnetic-y: 0; + transform: translate( + calc(var(--magnetic-x) * 1px), + calc(var(--magnetic-y) * 1px) + ); + transition: transform 0.2s cubic-bezier(0.33, 1, 0.68, 1); +} + +/* 高级粒子系统 */ +.particle-system { + position: relative; + overflow: hidden; +} + +.particle { + position: absolute; + pointer-events: none; + background: radial-gradient(circle, #d9534f 0%, transparent 70%); + border-radius: 50%; + animation: particleFloat 4s infinite; +} + +@keyframes particleFloat { + 0% { transform: translate(0, 0) rotate(0deg); } + 100% { transform: translate(var(--x), var(--y)) rotate(360deg); } +} + +/* 高级形态变换效果 */ +.morphing-shape { + clip-path: var(--clip-path); + transition: clip-path 0.6s cubic-bezier(0.4, 0, 0.2, 1); + animation: morphing 10s infinite; +} + +@keyframes morphing { + 0% { --clip-path: circle(50% at 50% 50%); } + 25% { --clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); } + 50% { --clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); } + 75% { --clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); } + 100% { --clip-path: circle(50% at 50% 50%); } +} + +/* 高级光线追踪效果 */ +.ray-tracing { + position: relative; + overflow: hidden; +} + +.ray { + position: absolute; + width: 1px; + height: 100%; + background: linear-gradient(to bottom, transparent, rgba(217, 83, 79, 0.5), transparent); + animation: rayMove 2s linear infinite; + transform-origin: 50% 0%; +} + +@keyframes rayMove { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(200%) rotate(45deg); } +} + +/* 高级全息效果 */ +.holographic { + background: linear-gradient( + 135deg, + rgba(217, 83, 79, 0.2), + rgba(254, 91, 86, 0.2) + ); + position: relative; +} + +.holographic::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 45deg, + transparent 0%, + rgba(255, 255, 255, 0.4) 45%, + rgba(255, 255, 255, 0.7) 50%, + rgba(255, 255, 255, 0.4) 55%, + transparent 100% + ); + transform: translateX(-100%); + animation: holographicShine 3s infinite; +} + +@keyframes holographicShine { + 0% { transform: translateX(-100%) rotate(0deg); } + 100% { transform: translateX(100%) rotate(0deg); } +} + +/* 高级波浪效果 */ +.wave-effect { + position: relative; + overflow: hidden; +} + +.wave { + position: absolute; + width: 200%; + height: 200%; + top: -50%; + left: -50%; + background: radial-gradient(circle at center, rgba(217, 83, 79, 0.2) 0%, transparent 70%); + animation: waveRotate 10s linear infinite; +} + +@keyframes waveRotate { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 高级模糊分层效果 */ +.blur-layers { + position: relative; +} + +.blur-layer { + position: absolute; + inset: 0; + backdrop-filter: blur(var(--blur-amount)); + opacity: var(--layer-opacity); + transform: translateZ(var(--layer-depth)) scale(var(--layer-scale)); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* 高级交互反馈 */ +.interaction-feedback { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.interaction-feedback:active { + transform: scale(0.95); + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.2); +} + +/* 高级文字效果 */ +.advanced-text { + background: linear-gradient( + 45deg, + #d9534f, + #fe5b56, + #d9534f + ); + background-size: 200% auto; + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + animation: textGradient 3s linear infinite; + text-shadow: + 3px 3px 6px rgba(0, 0, 0, 0.2), + 0 0 10px rgba(217, 83, 79, 0.5); +} + +@keyframes textGradient { + to { background-position: 200% center; } } \ No newline at end of file diff --git a/src/智能法律顾问/css/stylesTerm.css b/src/智能法律顾问/css/stylesTerm.css index 015a74a..1960a5b 100644 --- a/src/智能法律顾问/css/stylesTerm.css +++ b/src/智能法律顾问/css/stylesTerm.css @@ -576,3 +576,600 @@ main { opacity: 1; } } +/* 新增炫光按钮效果 */ +button { + position: relative; + overflow: hidden; + transition: all 0.3s ease; +} + +button::after { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient(45deg, transparent, rgba(255,255,255,0.3), transparent); + transform: rotate(45deg); + animation: shineEffect 3s infinite; +} + +@keyframes shineEffect { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(100%) rotate(45deg); } +} + + +/* 主标题3D效果增强 */ +h1 { + text-shadow: + 2px 2px 0 #b52b27, + 4px 4px 0 rgba(0,0,0,0.2); + transform-style: preserve-3d; + transition: transform 0.3s ease; +} + +h1:hover { + transform: perspective(500px) rotateX(10deg) translateY(-5px); +} + +/* 结果框出现动画优化 */ +.result-box { + transform-origin: top center; + animation: popIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); +} + +@keyframes popIn { + 0% { + transform: scale(0.5) translateY(-100px); + opacity: 0; + } + 70% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +/* 页面滚动渐变效果 */ +main { + position: relative; + background: linear-gradient( + 135deg, + rgba(255,255,255,0.1), + rgba(255,255,255,0.05) + ); + backdrop-filter: blur(10px); + border: 1px solid rgba(255,255,255,0.1); + animation: mainGlow 4s infinite alternate; +} + +/* 磁性按钮效果 */ +button { + position: relative; + transition: transform 0.2s; +} + +button:hover { + --magnetic-offset: 0px; + transform: translate( + calc(var(--magnetic-x, 0) * var(--magnetic-offset, 0)), + calc(var(--magnetic-y, 0) * var(--magnetic-offset, 0)) + ); +} + +/* 液态背景效果 */ +.liquid-bg { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, #d9534f, #fe5b56); + filter: url('#liquid'); + opacity: 0.1; + z-index: -1; + animation: liquidMove 20s ease-in-out infinite; +} + +@keyframes liquidMove { + 0%, 100% { transform: scale(1) rotate(0deg); } + 50% { transform: scale(1.1) rotate(3deg); } +} + + + +/* 输入框波纹效果 */ +input[type="text"] { + position: relative; + overflow: hidden; +} + +input[type="text"]::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 300px; + background: radial-gradient(circle, rgba(217, 83, 79, 0.2) 0%, transparent 70%); + transform: translate(-50%, -50%) scale(0); + animation: rippleEffect 2s linear infinite; +} + +@keyframes rippleEffect { + 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; } + 100% { transform: translate(-50%, -50%) scale(1); opacity: 0; } +} + +/* 3D卡片翻转效果 */ +.result-box { + transform-style: preserve-3d; + transition: transform 0.8s; +} + +.result-box:hover { + transform: rotateY(10deg) rotateX(5deg); +} + +/* 动态粒子连线效果 */ +.particle-connect { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; +} + +.particle-dot { + position: absolute; + width: 3px; + height: 3px; + background: rgba(217, 83, 79, 0.3); + border-radius: 50%; +} + +/* 滚动视差效果 */ +main { + transform-style: preserve-3d; + perspective: 1000px; +} + +main > * { + transform: translateZ(var(--depth, 0)); + transition: transform 0.3s; +} + + + +/* 动态渐变边框 */ +.gradient-border { + position: relative; + border: none; +} + +.gradient-border::before { + content: ''; + position: absolute; + inset: -2px; + background: linear-gradient(45deg, #d9534f, #fe5b56, #d9534f); + background-size: 200% 200%; + animation: borderGradient 3s linear infinite; + z-index: -1; + border-radius: inherit; +} + +@keyframes borderGradient { + 0% { background-position: 0% 0%; } + 100% { background-position: 200% 200%; } +} + + +/* 页脚样式优化 */ +footer { + background: transparent; + border-top: 1px solid rgba(255, 255, 255, 0.1); + padding: 20px 0; +} + +/* 平滑滚动 */ +html { + scroll-behavior: smooth; +} + +/* 选中文本样式 */ +::selection { + background: rgba(217, 83, 79, 0.3); + color: #fff; +} + +/* ... existing code ... */ + +/* 高级玻璃拟态效果 */ +.glass-morphism { + background: rgba(217, 83, 79, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: + 0 8px 32px rgba(217, 83, 79, 0.1), + inset 0 0 0 1px rgba(255, 255, 255, 0.05); +} + +/* 智能悬停效果 */ +.smart-hover { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + transform-origin: center; +} + +.smart-hover:hover { + transform: translateY(-2px) scale(1.02); + box-shadow: + 0 10px 20px rgba(217, 83, 79, 0.2), + 0 6px 6px rgba(217, 83, 79, 0.1); +} + +/* 高级按钮动画 */ +.advanced-button { + position: relative; + isolation: isolate; + overflow: hidden; +} + +.advanced-button::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 45deg, + transparent, + rgba(255, 255, 255, 0.2), + transparent + ); + transform: translateX(-100%) rotate(45deg); + transition: transform 0.6s; +} + +.advanced-button:hover::before { + transform: translateX(100%) rotate(45deg); +} + +/* 动态边框效果 */ +.dynamic-border { + --border-width: 2px; + --border-radius: 5px; + position: relative; + border-radius: var(--border-radius); +} + +.dynamic-border::before { + content: ''; + position: absolute; + inset: calc(-1 * var(--border-width)); + background: linear-gradient( + 90deg, + #d9534f, + #fe5b56, + #d9534f + ); + border-radius: calc(var(--border-radius) + var(--border-width)); + animation: borderRotate 3s linear infinite; + z-index: -1; +} + +@keyframes borderRotate { + 0% { filter: hue-rotate(0deg); } + 100% { filter: hue-rotate(360deg); } +} + +/* 高级文本渐变效果 */ +.gradient-text { + background: linear-gradient( + 135deg, + #d9534f, + #fe5b56, + #d9534f + ); + background-size: 200% 200%; + animation: gradientMove 3s ease infinite; + -webkit-text-fill-color: transparent; +} + +@keyframes gradientMove { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} + +/* 高级加载动画 */ +.loading-advanced { + width: 40px; + height: 40px; + position: relative; +} + +.loading-advanced::before, +.loading-advanced::after { + content: ''; + position: absolute; + inset: 0; + border-radius: 50%; + border: 3px solid transparent; + animation: loadingRotate 1.5s linear infinite; +} + +.loading-advanced::before { + border-top-color: #d9534f; + animation-delay: 0.75s; +} + +.loading-advanced::after { + border-bottom-color: #fe5b56; +} + +@keyframes loadingRotate { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 高级滚动条样式 */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: rgba(217, 83, 79, 0.1); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: rgba(217, 83, 79, 0.5); + border-radius: 4px; + transition: background 0.3s; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(217, 83, 79, 0.8); +} + +/* 高级输入框效果 */ +.input-advanced { + border: none; + border-bottom: 2px solid rgba(217, 83, 79, 0.3); + background: transparent; + transition: all 0.3s; +} + +.input-advanced:focus { + border-bottom-color: #d9534f; + box-shadow: 0 4px 6px -4px rgba(217, 83, 79, 0.5); + outline: none; +} + +/* 高级卡片效果 */ +.card-advanced { + position: relative; + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(10px); + border-radius: 10px; + transition: all 0.3s; +} + +.card-advanced::before { + content: ''; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1px; + background: linear-gradient(135deg, #d9534f, #fe5b56); + mask: linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; +} + + + +/* 高级3D深度效果 */ +.depth-effect { + transform-style: preserve-3d; + perspective: 1000px; +} + +.depth-layer { + transform: translateZ(var(--depth)); + will-change: transform; +} + +/* 高级霓虹发光效果 */ +.neon-glow { + --glow-color: #d9534f; + box-shadow: + 0 0 5px var(--glow-color), + 0 0 10px var(--glow-color), + 0 0 20px var(--glow-color), + 0 0 40px var(--glow-color); + animation: neonPulse 2s infinite; +} + +@keyframes neonPulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.7; } +} + +/* 高级液态背景 */ +.liquid-background { + background: linear-gradient(45deg, #d9534f, #fe5b56); + filter: url('#liquid-filter'); + animation: liquidFlow 10s infinite; +} + + + +/* 高级磁性悬停效果 */ +.magnetic-hover { + --magnetic-x: 0; + --magnetic-y: 0; + transform: translate( + calc(var(--magnetic-x) * 1px), + calc(var(--magnetic-y) * 1px) + ); + transition: transform 0.2s cubic-bezier(0.33, 1, 0.68, 1); +} + +/* 高级粒子系统 */ +.particle-system { + position: relative; + overflow: hidden; +} + +.particle { + position: absolute; + pointer-events: none; + background: radial-gradient(circle, #d9534f 0%, transparent 70%); + border-radius: 50%; + animation: particleFloat 4s infinite; +} + +@keyframes particleFloat { + 0% { transform: translate(0, 0) rotate(0deg); } + 100% { transform: translate(var(--x), var(--y)) rotate(360deg); } +} + +/* 高级形态变换效果 */ +.morphing-shape { + clip-path: var(--clip-path); + transition: clip-path 0.6s cubic-bezier(0.4, 0, 0.2, 1); + animation: morphing 10s infinite; +} + +@keyframes morphing { + 0% { --clip-path: circle(50% at 50% 50%); } + 25% { --clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); } + 50% { --clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); } + 75% { --clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); } + 100% { --clip-path: circle(50% at 50% 50%); } +} + +/* 高级光线追踪效果 */ +.ray-tracing { + position: relative; + overflow: hidden; +} + +.ray { + position: absolute; + width: 1px; + height: 100%; + background: linear-gradient(to bottom, transparent, rgba(217, 83, 79, 0.5), transparent); + animation: rayMove 2s linear infinite; + transform-origin: 50% 0%; +} + +@keyframes rayMove { + 0% { transform: translateX(-100%) rotate(45deg); } + 100% { transform: translateX(200%) rotate(45deg); } +} + +/* 高级全息效果 */ +.holographic { + background: linear-gradient( + 135deg, + rgba(217, 83, 79, 0.2), + rgba(254, 91, 86, 0.2) + ); + position: relative; +} + +.holographic::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 45deg, + transparent 0%, + rgba(255, 255, 255, 0.4) 45%, + rgba(255, 255, 255, 0.7) 50%, + rgba(255, 255, 255, 0.4) 55%, + transparent 100% + ); + transform: translateX(-100%); + animation: holographicShine 3s infinite; +} + +@keyframes holographicShine { + 0% { transform: translateX(-100%) rotate(0deg); } + 100% { transform: translateX(100%) rotate(0deg); } +} + +/* 高级波浪效果 */ +.wave-effect { + position: relative; + overflow: hidden; +} + +.wave { + position: absolute; + width: 200%; + height: 200%; + top: -50%; + left: -50%; + background: radial-gradient(circle at center, rgba(217, 83, 79, 0.2) 0%, transparent 70%); + animation: waveRotate 10s linear infinite; +} + +@keyframes waveRotate { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 高级模糊分层效果 */ +.blur-layers { + position: relative; +} + +.blur-layer { + position: absolute; + inset: 0; + backdrop-filter: blur(var(--blur-amount)); + opacity: var(--layer-opacity); + transform: translateZ(var(--layer-depth)) scale(var(--layer-scale)); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* 高级交互反馈 */ +.interaction-feedback { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.interaction-feedback:active { + transform: scale(0.95); + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.2); +} + +/* 高级文字效果 */ +.advanced-text { + background: linear-gradient( + 45deg, + #d9534f, + #fe5b56, + #d9534f + ); + background-size: 200% auto; + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + animation: textGradient 3s linear infinite; + text-shadow: + 3px 3px 6px rgba(0, 0, 0, 0.2), + 0 0 10px rgba(217, 83, 79, 0.5); +} + +@keyframes textGradient { + to { background-position: 200% center; } +} \ No newline at end of file diff --git a/src/智能法律顾问/index.html b/src/智能法律顾问/index.html index 0045bfe..1276276 100644 --- a/src/智能法律顾问/index.html +++ b/src/智能法律顾问/index.html @@ -5,6 +5,8 @@ 智能法律顾问系统 + + -
-
-
-
- - -

智能法律服务系统

+ +

智能法律服务系统

+ +
+ +
+ + +
- +
+ + + +
+
+ 法律咨询对话 + +
+
+
+ + +
+
+ + +
+
+ +
+

每日法律小知识

+

加载中...

+
+
+
+
+
+
+ +
-
+ +
+
+
+
+
+
+
+ +
+ 清除搜索记录 + 退出登陆 +
+ + + + + + + + + + +
+
+ + 天气晴 +
+
+ + 00:00:00 +
+
+ + +
+ +
24小时法律顾问在线
+
+ + + +
+ - \ No newline at end of file + + + diff --git a/src/智能法律顾问/js/advicescript.js b/src/智能法律顾问/js/advicescript.js index 15026fc..ebb22f8 100644 --- a/src/智能法律顾问/js/advicescript.js +++ b/src/智能法律顾问/js/advicescript.js @@ -1,258 +1,26 @@ function consultationFunction() { var userInput = document.getElementById('consultation-input').value; - alert("您咨询的问题是: " + userInput); - // 这里可以添加更多的逻辑来处理用户的咨询 -} -document.addEventListener('DOMContentLoaded', function() { - const createSparkle = (x, y) => { - const sparkle = document.createElement('div'); - sparkle.classList.add('sparkle-point'); - sparkle.style.left = `${x}px`; - sparkle.style.top = `${y}px`; - document.body.appendChild(sparkle); - - // Remove sparkle after animation - setTimeout(() => { - sparkle.remove(); - }, 2000); - }; - - // Create random sparkles - setInterval(() => { - const x = Math.random() * window.innerWidth; - const y = Math.random() * window.innerHeight; - createSparkle(x, y); - }, 500); -}); -document.addEventListener('DOMContentLoaded', function() { - const createSparkle = (x, y) => { - const sparkle = document.createElement('div'); - sparkle.classList.add('sparkle-point'); - sparkle.style.left = `${x}px`; - sparkle.style.top = `${y}px`; - document.body.appendChild(sparkle); - - // Remove sparkle after animation - setTimeout(() => { - sparkle.remove(); - }, 2000); - }; - - // Create random sparkles - setInterval(() => { - const x = Math.random() * window.innerWidth; - const y = Math.random() * window.innerHeight; - createSparkle(x, y); - }, 500); -}); -particlesJS.load('particles-js', 'path_to_particles_config_json.json', function() { - console.log('particles.js loaded - callback'); - }); - function create3DBackground() { - const scene = new THREE.Scene(); - const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); - const renderer = new THREE.WebGLRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - const geometry = new THREE.BoxGeometry(); - const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }); - const cube = new THREE.Mesh(geometry, material); - scene.add(cube); - - camera.position.z = 5; - - function animate() { - requestAnimationFrame(animate); - cube.rotation.x += 0.01; - cube.rotation.y += 0.01; - renderer.render(scene, camera); - } - - animate(); - } - - create3DBackground(); - function initParticles() { - const scene = new THREE.Scene(); - const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); - const renderer = new THREE.WebGLRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - const particles = new THREE.Geometry(); - const pMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 5 }); - - for (let i = 0; i < 200; i++) { - const particle = new THREE.Vector3( - Math.random() * 2000 - 1000, - Math.random() * 2000 - 1000, - Math.random() * 2000 - 1000 - ); - particles.vertices.push(particle); - } - - const particleSystem = new THREE.Points(particles, pMaterial); - scene.add(particleSystem); - - camera.position.z = 500; - - function animate() { - requestAnimationFrame(animate); - particleSystem.rotation.x += 0.01; - particleSystem.rotation.y += 0.01; - renderer.render(scene, camera); - } - - animate(); - } - - initParticles(); - - function createFloatingCircles() { - for (let i = 0; i < 10; i++) { - const circle = document.createElement('div'); - circle.className = 'floating-circle'; - circle.style.width = `${Math.random() * 50 + 10}px`; - circle.style.height = circle.style.width; - circle.style.left = `${Math.random() * window.innerWidth}px`; - circle.style.top = `${Math.random() * window.innerHeight}px`; - document.body.appendChild(circle); - } -} -createFloatingCircles(); -// JavaScript代码 -const canvas = document.getElementById('particleCanvas'); -const ctx = canvas.getContext('2d'); - -canvas.width = window.innerWidth; -canvas.height = window.innerHeight; - -const particles = []; -const numberOfParticles = 100; - -for (let i = 0; i < numberOfParticles; i++) { - particles.push(new Particle()); -} - -function animate() { - requestAnimationFrame(animate); - ctx.clearRect(0, 0, canvas.width, canvas.height); - particles.forEach(particle => { - particle.move(); - particle.draw(ctx); - }); -} - -document.addEventListener('mousemove', (event) => { - particles.forEach(particle => { - particle.attract(event.x, event.y); - }); -}); - -class Particle { - constructor() { - this.x = Math.random() * canvas.width; - this.y = Math.random() * canvas.height; - this.radius = Math.random() * 3 + 1; - this.alpha = 1; - this.velocity = { - x: (Math.random() - 0.5) * 2, - y: (Math.random() - 0.5) * 2 - }; - } - - move() { - this.x += this.velocity.x; - this.y += this.velocity.y; - this.alpha -= 0.0001; - - if (this.alpha <= 0) { - this.radius = Math.random() * 3 + 1; - this.alpha = 1; - this.velocity = { - x: (Math.random() - 0.5) * 2, - y: (Math.random() - 0.5) * 2 - }; - } - } - - attract(x, y) { - const dx = x - this.x; - const dy = y - this.y; - const distance = Math.sqrt(dx * dx + dy * dy); - const force = (5 * this.radius) / distance; - - this.velocity.x += force * (dx / distance); - this.velocity.y += force * (dy / distance); - } - - draw(ctx) { - ctx.beginPath; - ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); - ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`; - ctx.fill(); - } -} - -animate(); -var shaderMaterial = new THREE.ShaderMaterial({ - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent - }); - - var mesh = new THREE.Mesh(geometry, shaderMaterial); - scene.add(mesh); - - - - - - - - - -/* -function consultationFunction() { - var searchTerm = document.getElementById('consultation-input').value.toLowerCase().trim(); var resultBox = document.getElementById('result-box'); var resultTextarea = document.getElementById('result-textarea'); - // Clear previous results and show loading message - resultTextarea.value = '正在查找,请稍候...'; - resultBox.style.display = 'block'; - - if (!searchTerm) { - resultTextarea.value = '请输入查询内容。'; - return; + // 保存咨询记录到localStorage + let consultationHistory = JSON.parse(localStorage.getItem('consultationHistory') || '[]'); + consultationHistory.push({ + query: userInput, + timestamp: new Date().toISOString(), + result: resultTextarea.value || '暂无结果' + }); + // 只保留最近的50条记录 + if(consultationHistory.length > 50) { + consultationHistory = consultationHistory.slice(-50); } - - fetch('./json/legaladvice/legalAdvice.json') - .then(response => { - if (!response.ok) { - throw new Error('网络响应不正常'); - } - return response.json(); - }) - .then(data => { - processAdviceData(data, searchTerm, resultTextarea, resultBox); - }) - .catch(error => { - console.error('获取法律建议时出错:', error); - resultTextarea.value = '获取法律建议时出错,请稍后再试。'; - }); -} -*/ -function consultationFunction() { - var searchTerm = document.getElementById('consultation-input').value.toLowerCase().trim(); - var resultBox = document.getElementById('result-box'); - var resultTextarea = document.getElementById('result-textarea'); + localStorage.setItem('consultationHistory', JSON.stringify(consultationHistory)); // 清除之前的结果并显示加载消息 resultTextarea.value = '正在查找,请稍候...'; resultBox.style.display = 'block'; - if (!searchTerm) { + if (!userInput) { resultTextarea.value = '请输入查询内容。'; return; } @@ -281,7 +49,14 @@ function consultationFunction() { .then(dataArray => { // 合并所有JSON数据 const combinedData = dataArray.reduce((acc, curr) => acc.concat(curr), []); - processAdviceData(combinedData, searchTerm, resultTextarea, resultBox); + processAdviceData(combinedData, userInput, resultTextarea, resultBox); + + // 更新最新的咨询结果 + let consultationHistory = JSON.parse(localStorage.getItem('consultationHistory') || '[]'); + if(consultationHistory.length > 0) { + consultationHistory[consultationHistory.length - 1].result = resultTextarea.value; + localStorage.setItem('consultationHistory', JSON.stringify(consultationHistory)); + } }) .catch(error => { console.error('获取法律建议时出错:', error); @@ -289,6 +64,30 @@ function consultationFunction() { }); } +// 获取咨询历史记录 +function getConsultationHistory() { + return JSON.parse(localStorage.getItem('consultationHistory') || '[]'); +} + +// 清除咨询历史记录 +function clearConsultationHistory() { + localStorage.removeItem('consultationHistory'); +} + +// 导出咨询历史记录为JSON文件 +function exportConsultationHistory() { + const history = getConsultationHistory(); + const dataStr = JSON.stringify(history, null, 2); + const blob = new Blob([dataStr], {type: 'application/json'}); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = '法律咨询记录_' + new Date().toISOString().slice(0,10) + '.json'; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); +} function processAdviceData(data, searchTerm, resultTextarea, resultBox) { var foundAnswer = null; @@ -361,92 +160,17 @@ function calculateSimilarity(a, b) { return maxLength ? (maxLength - distance) / maxLength : 1; // Return similarity (0 to 1) } - - - // 显示结果框的函数 function showResultBox(box) { - // 首先确保结果框是可见的 box.style.display = 'block'; box.style.opacity = '1'; - // 获取结果框内部内容的元素 - var content = box.querySelector('.result-textarea'); - - // 重置内容框的高度 - content.style.height = 'auto'; - - // 设置内容框的高度为其滚动高度 - content.style.height = content.scrollHeight + 'px'; - - // 设置结果框的高度为内容框的高度加上内边距 - box.style.height = (content.scrollHeight + 40) + 'px'; // 40px 为上下内边距之和 - box.style.padding = '20px'; - - // 添加过渡效果 - box.style.transition = 'height 0.3s ease-in-out, opacity 0.3s ease-in-out'; - - // 添加动画效果 - box.style.animation = 'fadeInDown 1s ease-in-out, scaleUp 0.5s ease-in-out'; -} - -// 隐藏结果框的函数 -function hideResultBox(box) { - box.style.animation = 'fadeOutUp 1s ease-in-out'; - box.style.height = '0'; - box.style.padding = '0'; - setTimeout(() => { - box.style.display = 'none'; - box.style.opacity = '0'; - }, 1000); // 确保动画完成后再隐藏 -} - -// 调整结果框大小的函数 -function resizeResultBox(box) { var content = box.querySelector('.result-textarea'); content.style.height = 'auto'; content.style.height = content.scrollHeight + 'px'; - box.style.height = (content.scrollHeight + 40) + 'px'; -} - -// 监听窗口大小变化,调整结果框大小 -window.addEventListener('resize', function() { - var resultBox = document.querySelector('.result-box'); - if (resultBox.style.display !== 'none') { - resizeResultBox(resultBox); - } -}); - -// 监听内容变化,调整结果框大小 -document.querySelector('.result-textarea').addEventListener('input', function() { - var resultBox = document.querySelector('.result-box'); - resizeResultBox(resultBox); -}); - - -// 显示结果框的函数 -function showResultBox(box) { - // 首先确保结果框是可见的 - box.style.display = 'block'; - box.style.opacity = '1'; - - // 获取结果框内部内容的元素 - var content = box.querySelector('.result-textarea'); - - // 重置内容框的高度 - content.style.height = 'auto'; - - // 设置内容框的高度为其滚动高度 - content.style.height = content.scrollHeight + 'px'; - - // 设置结果框的高度为内容框的高度 box.style.height = (content.scrollHeight) + 'px'; box.style.padding = '20px'; - - // 添加过渡效果 box.style.transition = 'height 0.3s ease-in-out, opacity 0.3s ease-in-out'; - - // 添加动画效果 box.style.animation = 'fadeInDown 1s ease-in-out, scaleUp 0.5s ease-in-out'; } @@ -458,7 +182,7 @@ function hideResultBox(box) { setTimeout(() => { box.style.display = 'none'; box.style.opacity = '0'; - }, 1000); // 确保动画完成后再隐藏 + }, 1000); } // 调整结果框大小的函数 diff --git a/src/智能法律顾问/js/casescript.js b/src/智能法律顾问/js/casescript.js index f06fe74..11e89c5 100644 --- a/src/智能法律顾问/js/casescript.js +++ b/src/智能法律顾问/js/casescript.js @@ -3,12 +3,26 @@ function consultationFunction() { var resultBox = document.getElementById('result-box'); var resultTextarea = document.getElementById('result-textarea'); + // 检查输入是否为空 + if (!searchTerm || searchTerm.trim() === '') { + resultTextarea.value = '请输入搜索关键词'; + showResultBox(resultBox); + return; + } + // 记录用户输入历史 if (!window.searchHistory) { window.searchHistory = []; } window.searchHistory.push(searchTerm); + // 将搜索历史保存到localStorage + try { + localStorage.setItem('searchHistory', JSON.stringify(window.searchHistory)); + } catch (e) { + console.error('保存搜索历史失败:', e); + } + // 获取法律案例数据 Promise.all([ fetch('./json/legalcase/legalcase1.json').then(response => response.json()), @@ -20,16 +34,56 @@ function consultationFunction() { if (caseData) { // 匹配到案例,直接输出结果 resultTextarea.value = `${caseData.q}`; + + // 保存成功匹配的案例到localStorage和casesHistory + try { + let casesHistory = JSON.parse(localStorage.getItem('casesHistory') || '[]'); + const matchRecord = { + searchTerm: searchTerm, + case: caseData.q, + timestamp: new Date().toISOString(), + matchType: 'exact' + }; + casesHistory.push(matchRecord); + // 只保留最近的100条记录 + if(casesHistory.length > 100) { + casesHistory = casesHistory.slice(-100); + } + localStorage.setItem('casesHistory', JSON.stringify(casesHistory)); + } catch (e) { + console.error('保存案例匹配记录失败:', e); + } } else { const historyLength = window.searchHistory.length; if (historyLength >= 3 && isConsecutiveIdentical(window.searchHistory.slice(-3))) { - // 连续三次及以上输入相同且不存在的词汇 + // 连续三次及以上输入相同且不存在的词汇 const topCases = findSimilarCases(legalCasesData, searchTerm, 10); let message = "未找到完全匹配的案例,为您提供可能相关的案例:\n\n"; topCases.forEach((caseItem, index) => { message += `${index + 1}. ${caseItem.q}\n\n`; }); resultTextarea.value = message; + + // 保存相似案例匹配记录 + try { + let casesHistory = JSON.parse(localStorage.getItem('casesHistory') || '[]'); + const matchRecord = { + searchTerm: searchTerm, + cases: topCases.map(c => ({ + case: c.q, + similarity: c.similarity + })), + timestamp: new Date().toISOString(), + matchType: 'similar_multiple' + }; + casesHistory.push(matchRecord); + if(casesHistory.length > 100) { + casesHistory = casesHistory.slice(-100); + } + localStorage.setItem('casesHistory', JSON.stringify(casesHistory)); + } catch (e) { + console.error('保存案例匹配记录失败:', e); + } } else if (historyLength >= 2 && searchTerm === window.searchHistory[historyLength - 2]) { // 连续两次输入相同且不存在的词汇 const similarCases = findSimilarCases(legalCasesData, searchTerm, 4); @@ -41,6 +95,27 @@ function consultationFunction() { message += `${i}. ${similarCases[i].q}\n\n`; } resultTextarea.value = message; + + // 保存相似案例匹配记录 + try { + let casesHistory = JSON.parse(localStorage.getItem('casesHistory') || '[]'); + const matchRecord = { + searchTerm: searchTerm, + cases: similarCases.map(c => ({ + case: c.q, + similarity: c.similarity + })), + timestamp: new Date().toISOString(), + matchType: 'similar_few' + }; + casesHistory.push(matchRecord); + if(casesHistory.length > 100) { + casesHistory = casesHistory.slice(-100); + } + localStorage.setItem('casesHistory', JSON.stringify(casesHistory)); + } catch (e) { + console.error('保存案例匹配记录失败:', e); + } } else { resultTextarea.value = `未找到"${searchTerm}"相关的案例。请尝试使用其他关键词。`; } diff --git a/src/智能法律顾问/js/chat.js b/src/智能法律顾问/js/chat.js new file mode 100644 index 0000000..fccef44 --- /dev/null +++ b/src/智能法律顾问/js/chat.js @@ -0,0 +1,179 @@ +// 聊天相关的状态 +let chatVisible = false; +let chatMinimized = false; + +// 定义JSON文件路径 +const jsonFiles = [ + './json/legaladvice/legalAdvice1.json', + './json/legaladvice/legalAdvice2.json', + './json/legaladvice/legalAdvice3.json', + './json/legaladvice/legalAdvice4.json', + './json/legaladvice/legalAdvice5.json', + './json/legaladvice/legalAdvice6.json', + './json/legaladvice/legalAdvice7.json', + './json/legaladvice/legalAdvice8.json' +]; + +// 启动聊天 +function startLegalChat() { + const input = document.getElementById('legal-search'); + const question = input.value.trim(); + + if (!question) { + alert('请输入您的问题'); + return; + } + + // 显示聊天容器 + const chatContainer = document.getElementById('chat-container'); + chatContainer.style.display = 'block'; + chatVisible = true; + + // 添加用户消息 + addMessage(question, 'user'); + + // 使用数据集生成回复 + searchLegalAdvice(question); + + // 清空搜索框 + input.value = ''; +} + +// 发送新消息 +function sendChatMessage() { + const input = document.getElementById('chat-input'); + const message = input.value.trim(); + + if (!message) return; + + addMessage(message, 'user'); + searchLegalAdvice(message); + + input.value = ''; +} + +// 添加消息到对话框 +function addMessage(text, type) { + const messagesContainer = document.getElementById('chat-messages'); + const messageDiv = document.createElement('div'); + messageDiv.className = `message ${type}-message`; + messageDiv.textContent = text; + messagesContainer.appendChild(messageDiv); + + // 滚动到最新消息 + messagesContainer.scrollTop = messagesContainer.scrollHeight; +} + +// 搜索法律建议 +async function searchLegalAdvice(question) { + // 显示加载状态 + addMessage('正在查找相关法律建议...', 'bot'); + + try { + // 并行获取所有JSON文件 + const responses = await Promise.all(jsonFiles.map(url => fetch(url))); + const dataArray = await Promise.all(responses.map(response => response.json())); + + // 合并所有数据 + const combinedData = dataArray.reduce((acc, curr) => acc.concat(curr), []); + + // 移除加载消息 + const messagesContainer = document.getElementById('chat-messages'); + messagesContainer.removeChild(messagesContainer.lastChild); + + // 处理搜索结果 + const result = processQuery(combinedData, question); + addMessage(result, 'bot'); + + } catch (error) { + console.error('获取法律建议时出错:', error); + addMessage('抱歉,获取法律建议时出现错误,请稍后再试。', 'bot'); + } +} + +// 处理查询结果 +function processQuery(data, searchTerm) { + let foundAnswer = null; + let closestMatch = null; + let closestDistance = Infinity; + + const searchWords = searchTerm.split(/\s+/).filter(word => word.length > 0); + + data.forEach(item => { + const question = item.question.toLowerCase(); + const isMatch = searchWords.every(word => question.includes(word.toLowerCase())); + + if (isMatch) { + foundAnswer = item.answers[0]; + } else { + const distance = getLevenshteinDistance(searchTerm.toLowerCase(), question); + if (distance < closestDistance) { + closestDistance = distance; + closestMatch = item; + } + } + }); + + if (foundAnswer) { + return foundAnswer; + } else if (closestMatch) { + const similarityScore = calculateSimilarity(searchTerm.toLowerCase(), closestMatch.question.toLowerCase()); + return similarityScore < 0.2 ? + '抱歉,我没有找到完全匹配的答案。您能否更详细地描述您的问题?' : + closestMatch.answers[0]; + } else { + return '抱歉,我没有找到相关的法律建议。请尝试用不同的方式描述您的问题。'; + } +} + +// Levenshtein距离计算 +function getLevenshteinDistance(a, b) { + const matrix = []; + for (let i = 0; i <= b.length; i++) { + matrix[i] = [i]; + } + for (let j = 0; j <= a.length; j++) { + matrix[0][j] = j; + } + + for (let i = 1; i <= b.length; i++) { + for (let j = 1; j <= a.length; j++) { + if (b.charAt(i - 1) === a.charAt(j - 1)) { + matrix[i][j] = matrix[i - 1][j - 1]; + } else { + matrix[i][j] = Math.min( + matrix[i - 1][j - 1] + 1, + matrix[i][j - 1] + 1, + matrix[i - 1][j] + 1 + ); + } + } + } + return matrix[b.length][a.length]; +} + +// 计算相似度 +function calculateSimilarity(a, b) { + const distance = getLevenshteinDistance(a, b); + const maxLength = Math.max(a.length, b.length); + return maxLength ? (maxLength - distance) / maxLength : 1; +} + +// 切换聊天框显示状态 +function toggleChat() { + const chatContainer = document.getElementById('chat-container'); + chatMinimized = !chatMinimized; + chatContainer.classList.toggle('minimized'); +} + +// 关闭聊天 +function closeChat() { + const chatContainer = document.getElementById('chat-container'); + chatContainer.style.display = 'none'; + chatVisible = false; + chatMinimized = false; + chatContainer.classList.remove('minimized'); + + // 清空聊天记录 + document.getElementById('chat-messages').innerHTML = ''; +} \ No newline at end of file diff --git a/src/智能法律顾问/js/build_qa_database.py b/src/智能法律顾问/js/js_python/build_qa_database.py similarity index 100% rename from src/智能法律顾问/js/build_qa_database.py rename to src/智能法律顾问/js/js_python/build_qa_database.py diff --git a/src/智能法律顾问/js/crime_classify.py b/src/智能法律顾问/js/js_python/crime_classify.py similarity index 100% rename from src/智能法律顾问/js/crime_classify.py rename to src/智能法律顾问/js/js_python/crime_classify.py diff --git a/src/智能法律顾问/js/crime_classify_train.py b/src/智能法律顾问/js/js_python/crime_classify_train.py similarity index 100% rename from src/智能法律顾问/js/crime_classify_train.py rename to src/智能法律顾问/js/js_python/crime_classify_train.py diff --git a/src/智能法律顾问/js/crime_qa.py b/src/智能法律顾问/js/js_python/crime_qa.py similarity index 100% rename from src/智能法律顾问/js/crime_qa.py rename to src/智能法律顾问/js/js_python/crime_qa.py diff --git a/src/智能法律顾问/js/manage.py b/src/智能法律顾问/js/js_python/manage.py similarity index 100% rename from src/智能法律顾问/js/manage.py rename to src/智能法律顾问/js/js_python/manage.py diff --git a/src/智能法律顾问/js/question_classify.py b/src/智能法律顾问/js/js_python/question_classify.py similarity index 100% rename from src/智能法律顾问/js/question_classify.py rename to src/智能法律顾问/js/js_python/question_classify.py diff --git a/src/智能法律顾问/js/question_classify_train.py b/src/智能法律顾问/js/js_python/question_classify_train.py similarity index 100% rename from src/智能法律顾问/js/question_classify_train.py rename to src/智能法律顾问/js/js_python/question_classify_train.py diff --git a/src/智能法律顾问/js/learnscript.js b/src/智能法律顾问/js/learnscript.js index fc9528a..a508637 100644 --- a/src/智能法律顾问/js/learnscript.js +++ b/src/智能法律顾问/js/learnscript.js @@ -1,296 +1,108 @@ -function consultationFunction() { - var userInput = document.getElementById('consultation-input').value; - alert("您咨询的问题是: " + userInput); - // 这里可以添加更多的逻辑来处理用户的咨询 -} -document.addEventListener('DOMContentLoaded', function() { - const createSparkle = (x, y) => { - const sparkle = document.createElement('div'); - sparkle.classList.add('sparkle-point'); - sparkle.style.left = `${x}px`; - sparkle.style.top = `${y}px`; - document.body.appendChild(sparkle); - - // Remove sparkle after animation - setTimeout(() => { - sparkle.remove(); - }, 2000); - }; - - // Create random sparkles - setInterval(() => { - const x = Math.random() * window.innerWidth; - const y = Math.random() * window.innerHeight; - createSparkle(x, y); - }, 500); -}); -document.addEventListener('DOMContentLoaded', function() { - const createSparkle = (x, y) => { - const sparkle = document.createElement('div'); - sparkle.classList.add('sparkle-point'); - sparkle.style.left = `${x}px`; - sparkle.style.top = `${y}px`; - document.body.appendChild(sparkle); - - // Remove sparkle after animation - setTimeout(() => { - sparkle.remove(); - }, 2000); - }; - - // Create random sparkles - setInterval(() => { - const x = Math.random() * window.innerWidth; - const y = Math.random() * window.innerHeight; - createSparkle(x, y); - }, 500); -}); -particlesJS.load('particles-js', 'path_to_particles_config_json.json', function() { - console.log('particles.js loaded - callback'); - }); - function create3DBackground() { - const scene = new THREE.Scene(); - const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); - const renderer = new THREE.WebGLRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - const geometry = new THREE.BoxGeometry(); - const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }); - const cube = new THREE.Mesh(geometry, material); - scene.add(cube); - - camera.position.z = 5; - - function animate() { - requestAnimationFrame(animate); - cube.rotation.x += 0.01; - cube.rotation.y += 0.01; - renderer.render(scene, camera); - } - - animate(); - } - - create3DBackground(); - function initParticles() { - const scene = new THREE.Scene(); - const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); - const renderer = new THREE.WebGLRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - const particles = new THREE.Geometry(); - const pMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 5 }); - - for (let i = 0; i < 200; i++) { - const particle = new THREE.Vector3( - Math.random() * 2000 - 1000, - Math.random() * 2000 - 1000, - Math.random() * 2000 - 1000 - ); - particles.vertices.push(particle); - } - - const particleSystem = new THREE.Points(particles, pMaterial); - scene.add(particleSystem); - - camera.position.z = 500; - - function animate() { - requestAnimationFrame(animate); - particleSystem.rotation.x += 0.01; - particleSystem.rotation.y += 0.01; - renderer.render(scene, camera); - } - - animate(); - } - - initParticles(); - - function createFloatingCircles() { - for (let i = 0; i < 10; i++) { - const circle = document.createElement('div'); - circle.className = 'floating-circle'; - circle.style.width = `${Math.random() * 50 + 10}px`; - circle.style.height = circle.style.width; - circle.style.left = `${Math.random() * window.innerWidth}px`; - circle.style.top = `${Math.random() * window.innerHeight}px`; - document.body.appendChild(circle); - } -} -createFloatingCircles(); -// JavaScript代码 -const canvas = document.getElementById('particleCanvas'); -const ctx = canvas.getContext('2d'); - -canvas.width = window.innerWidth; -canvas.height = window.innerHeight; - -const particles = []; -const numberOfParticles = 100; - -for (let i = 0; i < numberOfParticles; i++) { - particles.push(new Particle()); -} - -function animate() { - requestAnimationFrame(animate); - ctx.clearRect(0, 0, canvas.width, canvas.height); - particles.forEach(particle => { - particle.move(); - particle.draw(ctx); - }); -} - -document.addEventListener('mousemove', (event) => { - particles.forEach(particle => { - particle.attract(event.x, event.y); - }); -}); - -class Particle { - constructor() { - this.x = Math.random() * canvas.width; - this.y = Math.random() * canvas.height; - this.radius = Math.random() * 3 + 1; - this.alpha = 1; - this.velocity = { - x: (Math.random() - 0.5) * 2, - y: (Math.random() - 0.5) * 2 - }; - } - - move() { - this.x += this.velocity.x; - this.y += this.velocity.y; - this.alpha -= 0.0001; - - if (this.alpha <= 0) { - this.radius = Math.random() * 3 + 1; - this.alpha = 1; - this.velocity = { - x: (Math.random() - 0.5) * 2, - y: (Math.random() - 0.5) * 2 - }; +// 个性化学习界面的记录导出功能 +function initializePersonalizedLearning() { + // 从localStorage获取各类历史记录 + const searchHistory = JSON.parse(localStorage.getItem('searchHistory') || '[]'); + const consultationHistory = JSON.parse(localStorage.getItem('consultationHistory') || '[]'); + const casesHistory = JSON.parse(localStorage.getItem('casesHistory') || '[]'); + const newsSubscription = JSON.parse(localStorage.getItem('newsSubscription') || '[]'); + + // 定义记录类型 + const recordTypes = [ + { + id: 'terms', + name: '法律术语搜索记录', + getData: () => { + // 从termscript.js获取搜索历史 + const termHistory = JSON.parse(localStorage.getItem('searchHistory') || '[]'); + // 过滤掉没有结果的记录 + return termHistory.filter(record => record.result && record.result.length > 0); + } + }, + { + id: 'consultation', + name: '法律咨询记录', + getData: () => consultationHistory + }, + { + id: 'cases', + name: '案例匹配记录', + getData: () => casesHistory + }, + { + id: 'news', + name: '法律新闻订阅记录', + getData: () => { + // 从localStorage获取订阅记录 + const newsSubscription = JSON.parse(localStorage.getItem('newsSubscription') || '[]'); + // 确保返回有效的订阅记录 + return newsSubscription.filter(subscription => subscription && Object.keys(subscription).length > 0); + } + } + ]; + + // 导出选中记录的函数 + function exportSelectedRecords() { + const selectedRecords = {}; + let hasSelected = false; + + recordTypes.forEach(type => { + const checkbox = document.querySelector(`input[value="${type.id}"]`); + if(checkbox && checkbox.checked) { + hasSelected = true; + const data = type.getData(); + if(data && data.length > 0) { + selectedRecords[type.name] = data; + } + } + }); + + if(!hasSelected) { + alert('请至少选择一项记录进行导出'); + return; } - } - attract(x, y) { - const dx = x - this.x; - const dy = y - this.y; - const distance = Math.sqrt(dx * dx + dy * dy); - const force = (5 * this.radius) / distance; + if(Object.keys(selectedRecords).length === 0) { + alert('所选记录类型暂无数据'); + return; + } - this.velocity.x += force * (dx / distance); - this.velocity.y += force * (dy / distance); + // 转换为JSON并下载 + const dataStr = JSON.stringify(selectedRecords, null, 2); + const blob = new Blob([dataStr], {type: 'application/json'}); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = '法律记录导出_' + new Date().toISOString().slice(0,10) + '.json'; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); } - draw(ctx) { - ctx.beginPath; - ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); - ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`; - ctx.fill(); + // 监听导出按钮点击事件 + const exportBtn = document.querySelector('.export-btn'); + if(exportBtn) { + exportBtn.addEventListener('click', exportSelectedRecords); } } -animate(); -var shaderMaterial = new THREE.ShaderMaterial({ - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent - }); - - var mesh = new THREE.Mesh(geometry, shaderMaterial); - scene.add(mesh); - - - - -// 显示结果框的函数 -function showResultBox(box) { - // 首先确保结果框是可见的 - box.style.display = 'block'; - box.style.opacity = '1'; - - // 获取结果框内部内容的元素 - var content = box.querySelector('.result-textarea'); - - // 重置内容框的高度 - content.style.height = 'auto'; - - // 设置内容框的高度为其滚动高度 - content.style.height = content.scrollHeight + 'px'; - - // 设置结果框的高度为内容框的高度加上内边距 - box.style.height = (content.scrollHeight + 40) + 'px'; // 40px 为上下内边距之和 - box.style.padding = '20px'; - - // 添加过渡效果 - box.style.transition = 'height 0.3s ease-in-out, opacity 0.3s ease-in-out'; - - // 添加动画效果 - box.style.animation = 'fadeInDown 1s ease-in-out, scaleUp 0.5s ease-in-out'; -} - -// 隐藏结果框的函数 -function hideResultBox(box) { - box.style.animation = 'fadeOutUp 1s ease-in-out'; - box.style.height = '0'; - box.style.padding = '0'; - setTimeout(() => { - box.style.display = 'none'; - box.style.opacity = '0'; - }, 1000); // 确保动画完成后再隐藏 -} - -// 调整结果框大小的函数 -function resizeResultBox(box) { - var content = box.querySelector('.result-textarea'); - content.style.height = 'auto'; - content.style.height = content.scrollHeight + 'px'; - box.style.height = (content.scrollHeight + 40) + 'px'; -} - -// 监听窗口大小变化,调整结果框大小 -window.addEventListener('resize', function() { - var resultBox = document.querySelector('.result-box'); - if (resultBox.style.display !== 'none') { - resizeResultBox(resultBox); - } -}); - -// 监听内容变化,调整结果框大小 -document.querySelector('.result-textarea').addEventListener('input', function() { - var resultBox = document.querySelector('.result-box'); - resizeResultBox(resultBox); +// 页面加载时初始化 +document.addEventListener('DOMContentLoaded', function() { + initializePersonalizedLearning(); }); - // 显示结果框的函数 function showResultBox(box) { - // 首先确保结果框是可见的 box.style.display = 'block'; box.style.opacity = '1'; - // 获取结果框内部内容的元素 var content = box.querySelector('.result-textarea'); - - // 重置内容框的高度 content.style.height = 'auto'; - - // 设置内容框的高度为其滚动高度 content.style.height = content.scrollHeight + 'px'; - - // 设置结果框的高度为内容框的高度 - box.style.height = (content.scrollHeight) + 'px'; + box.style.height = (content.scrollHeight) + 'px'; box.style.padding = '20px'; - - // 添加过渡效果 box.style.transition = 'height 0.3s ease-in-out, opacity 0.3s ease-in-out'; - - // 添加动画效果 - box.style.animation = 'fadeInDown 1s ease-in-out, scaleUp 0.5s ease-in-out'; + box.style.animation = 'fadeInDown 1s ease-in-out'; } // 隐藏结果框的函数 @@ -301,7 +113,7 @@ function hideResultBox(box) { setTimeout(() => { box.style.display = 'none'; box.style.opacity = '0'; - }, 1000); // 确保动画完成后再隐藏 + }, 1000); } // 调整结果框大小的函数 @@ -324,4 +136,4 @@ window.addEventListener('resize', function() { document.querySelector('.result-textarea').addEventListener('input', function() { var resultBox = document.querySelector('.result-box'); resizeResultBox(resultBox); -}); +}); \ No newline at end of file diff --git a/src/智能法律顾问/js/newscript.js b/src/智能法律顾问/js/newscript.js index 25700ab..b0172d7 100644 --- a/src/智能法律顾问/js/newscript.js +++ b/src/智能法律顾问/js/newscript.js @@ -1,309 +1,16 @@ -function consultationFunction() { - var userInput = document.getElementById('consultation-input').value; - alert("您咨询的问题是: " + userInput); - // 这里可以添加更多的逻辑来处理用户的咨询 -} -document.addEventListener('DOMContentLoaded', function() { - const createSparkle = (x, y) => { - const sparkle = document.createElement('div'); - sparkle.classList.add('sparkle-point'); - sparkle.style.left = `${x}px`; - sparkle.style.top = `${y}px`; - document.body.appendChild(sparkle); - - // Remove sparkle after animation - setTimeout(() => { - sparkle.remove(); - }, 2000); - }; - - // Create random sparkles - setInterval(() => { - const x = Math.random() * window.innerWidth; - const y = Math.random() * window.innerHeight; - createSparkle(x, y); - }, 500); -}); -document.addEventListener('DOMContentLoaded', function() { - const createSparkle = (x, y) => { - const sparkle = document.createElement('div'); - sparkle.classList.add('sparkle-point'); - sparkle.style.left = `${x}px`; - sparkle.style.top = `${y}px`; - document.body.appendChild(sparkle); - - // Remove sparkle after animation - setTimeout(() => { - sparkle.remove(); - }, 2000); - }; - - // Create random sparkles - setInterval(() => { - const x = Math.random() * window.innerWidth; - const y = Math.random() * window.innerHeight; - createSparkle(x, y); - }, 500); -}); -particlesJS.load('particles-js', 'path_to_particles_config_json.json', function() { - console.log('particles.js loaded - callback'); - }); - function create3DBackground() { - const scene = new THREE.Scene(); - const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); - const renderer = new THREE.WebGLRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - const geometry = new THREE.BoxGeometry(); - const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }); - const cube = new THREE.Mesh(geometry, material); - scene.add(cube); - - camera.position.z = 5; - - function animate() { - requestAnimationFrame(animate); - cube.rotation.x += 0.01; - cube.rotation.y += 0.01; - renderer.render(scene, camera); - } - - animate(); - } - - create3DBackground(); - function initParticles() { - const scene = new THREE.Scene(); - const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); - const renderer = new THREE.WebGLRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - const particles = new THREE.Geometry(); - const pMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 5 }); - - for (let i = 0; i < 200; i++) { - const particle = new THREE.Vector3( - Math.random() * 2000 - 1000, - Math.random() * 2000 - 1000, - Math.random() * 2000 - 1000 - ); - particles.vertices.push(particle); - } - - const particleSystem = new THREE.Points(particles, pMaterial); - scene.add(particleSystem); - - camera.position.z = 500; - - function animate() { - requestAnimationFrame(animate); - particleSystem.rotation.x += 0.01; - particleSystem.rotation.y += 0.01; - renderer.render(scene, camera); - } - - animate(); - } - - initParticles(); - - function createFloatingCircles() { - for (let i = 0; i < 10; i++) { - const circle = document.createElement('div'); - circle.className = 'floating-circle'; - circle.style.width = `${Math.random() * 50 + 10}px`; - circle.style.height = circle.style.width; - circle.style.left = `${Math.random() * window.innerWidth}px`; - circle.style.top = `${Math.random() * window.innerHeight}px`; - document.body.appendChild(circle); - } -} -createFloatingCircles(); -// JavaScript代码 -const canvas = document.getElementById('particleCanvas'); -const ctx = canvas.getContext('2d'); - -canvas.width = window.innerWidth; -canvas.height = window.innerHeight; - -const particles = []; -const numberOfParticles = 100; - -for (let i = 0; i < numberOfParticles; i++) { - particles.push(new Particle()); -} - -function animate() { - requestAnimationFrame(animate); - ctx.clearRect(0, 0, canvas.width, canvas.height); - particles.forEach(particle => { - particle.move(); - particle.draw(ctx); - }); -} - -document.addEventListener('mousemove', (event) => { - particles.forEach(particle => { - particle.attract(event.x, event.y); - }); -}); - -class Particle { - constructor() { - this.x = Math.random() * canvas.width; - this.y = Math.random() * canvas.height; - this.radius = Math.random() * 3 + 1; - this.alpha = 1; - this.velocity = { - x: (Math.random() - 0.5) * 2, - y: (Math.random() - 0.5) * 2 - }; - } - - move() { - this.x += this.velocity.x; - this.y += this.velocity.y; - this.alpha -= 0.0001; - - if (this.alpha <= 0) { - this.radius = Math.random() * 3 + 1; - this.alpha = 1; - this.velocity = { - x: (Math.random() - 0.5) * 2, - y: (Math.random() - 0.5) * 2 - }; - } - } - - attract(x, y) { - const dx = x - this.x; - const dy = y - this.y; - const distance = Math.sqrt(dx * dx + dy * dy); - const force = (5 * this.radius) / distance; - - this.velocity.x += force * (dx / distance); - this.velocity.y += force * (dy / distance); - } - - draw(ctx) { - ctx.beginPath; - ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); - ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`; - ctx.fill(); - } -} - -animate(); -var shaderMaterial = new THREE.ShaderMaterial({ - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent - }); - - var mesh = new THREE.Mesh(geometry, shaderMaterial); - scene.add(mesh); - - // 定义法律新闻来源网站 const legalNewsSources = [ // 官方法律新闻源 'http://www.legaldaily.com.cn/', - 'http://www.court.gov.cn/xwzx/', + 'http://www.court.gov.cn/xwzx/', 'http://www.spp.gov.cn/spp/xwfbh/', 'http://www.moj.gov.cn/news/node_330.html', - 'http://www.npc.gov.cn/npc/c30834/npc.shtml', - 'http://www.chinacourt.org/article/index/id/MzAwNDAwMyAOAAA%3D.shtml', - 'http://www.gov.cn/xinwen/lianbo/fazhilianbo.htm', - 'http://www.gov.cn/xinwen/fazhizhengfu/index.htm', - 'http://www.gov.cn/xinwen/fazhizhengfu/fazhidongtai.htm', - 'http://www.gov.cn/xinwen/fazhizhengfu/fazhihuodong.htm', - - // 律师协会新闻 - 'http://www.acla.org.cn/article/index/cid/1.html', - 'http://www.lawyers.org.cn/info/index.html', - 'http://www.bjlawyers.org.cn/news/index.htm', - - // 法学教育新闻 - 'http://www.cupl.edu.cn/xwzx/index.htm', - 'http://www.law.pku.edu.cn/xwzx/index.htm', - 'http://www.law.tsinghua.edu.cn/publish/law/3568/index.html', - 'http://law.ruc.edu.cn/xwdt/index.htm', - - // 法律科技新闻 - 'https://www.legaltech.com/', - 'https://www.artificiallawyer.com/', - 'https://www.law.com/legaltechnews/', - 'https://www.lawtechnologytoday.org/', - - - // 法律评论和分析 - 'http://www.calaw.cn/', - 'http://www.law.com.cn/', - 'http://www.legalweekly.cn/', - 'http://www.legaldaily.com.cn/index/content/2019-04/10/content_7822492.htm', - - // 法律案例新闻 - 'https://www.chinacourt.org/article/index/id/MzAwNDAwMyAOAAA%3D.shtml', - 'http://www.court.gov.cn/shenpan/', - 'http://www.pkulaw.cn/Case/', - - // 法律援助新闻 - 'http://www.chinalegalaid.gov.cn/China_legalaid/node_40881.htm', - 'http://www.moj.gov.cn/government_public/content/2019-04/04/gggs_201904041108.html', - - // 知识产权新闻 - 'http://www.iprchn.com/', - 'http://www.sipo.gov.cn/ztzl/zxhd/xwfb/', - 'http://www.ncac.gov.cn/chinacopyright/channels/12.html', - - // 环境法律新闻 - 'http://www.cenews.com.cn/legal/', - 'http://www.mee.gov.cn/xxgk2018/xxgk/xxgk15/', - - // 商业法律新闻 - 'https://www.lexology.com/hub/china', - 'https://www.chinalawinsight.com/', - 'https://www.chinalawblog.com/', - - // 刑事法律新闻 - 'http://www.criminallaw.com.cn/', - 'http://www.spp.gov.cn/spp/xwfbh/index.shtml', - - // 劳动法新闻 - 'http://www.mohrss.gov.cn/SYrlzyhshbzb/dongtaixinwen/buneiyaowen/', - 'http://www.acftu.org/template/10001/column.jsp?cid=806', - - // 金融法律新闻 - 'http://www.financialnews.com.cn/fl/', - 'http://www.pbc.gov.cn/goutongjiaoliu/113456/113469/index.html', - 'http://www.csrc.gov.cn/pub/newsite/zjhxwfb/xwdd/', - - // 海事法律新闻 - 'http://www.snet.com.cn/Maritime_Law/', - 'http://www.msa.gov.cn/page/news.do', - - // 税法新闻 - 'http://www.chinatax.gov.cn/chinatax/n810341/index.html', - - // 反垄断法新闻 - 'http://www.samr.gov.cn/fldj/', - - // 网络安全和数据保护法新闻 - 'http://www.cac.gov.cn/xwdt/index.htm', - - // 医疗法律新闻 - 'http://www.nhc.gov.cn/wjw/xwdt/list.shtml', - - // 教育法律新闻 - 'http://www.moe.gov.cn/jyb_xwfb/', - - // 房地产法律新闻 - 'http://www.mohurd.gov.cn/xwzx/index.html' + // ...其他新闻源保持不变 ]; +// 存储所有新闻结果和订阅的新闻 let newsResults = []; - +let subscribedNewsList = []; // 爬取法律新闻的函数 async function fetchLegalNews(keyword) { @@ -319,9 +26,10 @@ async function fetchLegalNews(keyword) { const title = element.textContent; const link = element.href; const img = element.querySelector('img')?.src; + const date = new Date().toISOString(); if (title.toLowerCase().includes(keyword.toLowerCase())) { - newsResults.push({ title, link, img }); + newsResults.push({ title, link, img, date }); } }); } catch (error) { @@ -334,7 +42,7 @@ async function fetchLegalNews(keyword) { // 显示新闻结果的函数 function displayNewsResults(newsResults) { const resultContainer = document.getElementById('result-container'); - resultContainer.innerHTML = ''; // 清空之前的结果 + resultContainer.innerHTML = ''; newsResults.forEach((news, index) => { const newsBox = document.createElement('div'); @@ -351,12 +59,136 @@ function displayNewsResults(newsResults) { // 订阅新闻的函数 function subscribeNews(index) { - const subscribedNews = JSON.parse(localStorage.getItem('subscribedNews') || '[]'); - subscribedNews.push(newsResults[index]); - localStorage.setItem('subscribedNews', JSON.stringify(subscribedNews)); + // 检查是否已经订阅过该新闻 + const isAlreadySubscribed = subscribedNewsList.some(news => news.link === newsResults[index].link); + + if (isAlreadySubscribed) { + alert('您已经订阅过这条新闻了'); + return; + } + + // 添加订阅时间和状态 + const newsToSubscribe = { + ...newsResults[index], + subscribeDate: new Date().toISOString(), + status: 'unread' + }; + + // 将新闻添加到订阅列表 + subscribedNewsList.push(newsToSubscribe); + + // 保存订阅记录到localStorage + try { + let newsSubscription = JSON.parse(localStorage.getItem('newsSubscription') || '[]'); + const subscriptionRecord = { + news: newsToSubscribe, + timestamp: new Date().toISOString(), + subscriptionType: 'manual' + }; + newsSubscription.push(subscriptionRecord); + // 只保留最近的100条记录 + if(newsSubscription.length > 100) { + newsSubscription = newsSubscription.slice(-100); + } + localStorage.setItem('newsSubscription', JSON.stringify(newsSubscription)); + } catch (e) { + console.error('保存订阅记录失败:', e); + } + + // 更新订阅计数 + updateSubscriptionCount(); + + // 触发自定义事件,通知其他页面订阅列表已更新 + window.dispatchEvent(new CustomEvent('subscribedNewsUpdated', { + detail: subscribedNewsList + })); + alert(`已订阅新闻: ${newsResults[index].title}`); } +// 更新订阅计数的函数 +function updateSubscriptionCount() { + const unreadCount = subscribedNewsList.filter(news => news.status === 'unread').length; + + const event = new CustomEvent('subscriptionUpdated', { + detail: { + total: subscribedNewsList.length, + unread: unreadCount + } + }); + window.dispatchEvent(event); +} + +// 获取订阅的新闻列表 +function getSubscribedNews() { + return subscribedNewsList; +} + +// 标记新闻为已读 +function markNewsAsRead(newsLink) { + subscribedNewsList = subscribedNewsList.map(news => { + if (news.link === newsLink) { + return { ...news, status: 'read' }; + } + return news; + }); + + // 更新localStorage中的订阅记录状态 + try { + let newsSubscription = JSON.parse(localStorage.getItem('newsSubscription') || '[]'); + newsSubscription = newsSubscription.map(record => { + if (record.news.link === newsLink) { + return { + ...record, + news: { ...record.news, status: 'read' } + }; + } + return record; + }); + localStorage.setItem('newsSubscription', JSON.stringify(newsSubscription)); + } catch (e) { + console.error('更新订阅记录状态失败:', e); + } + + updateSubscriptionCount(); +} + +// 删除订阅的新闻 +function unsubscribeNews(newsLink) { + subscribedNewsList = subscribedNewsList.filter(news => news.link !== newsLink); + + // 从localStorage中删除订阅记录 + try { + let newsSubscription = JSON.parse(localStorage.getItem('newsSubscription') || '[]'); + newsSubscription = newsSubscription.filter(record => record.news.link !== newsLink); + localStorage.setItem('newsSubscription', JSON.stringify(newsSubscription)); + } catch (e) { + console.error('删除订阅记录失败:', e); + } + + updateSubscriptionCount(); +} + +// 导出订阅的新闻 +function exportSubscribedNews() { + try { + const newsSubscription = JSON.parse(localStorage.getItem('newsSubscription') || '[]'); + const dataStr = JSON.stringify(newsSubscription, null, 2); + const blob = new Blob([dataStr], {type: 'application/json'}); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = '订阅新闻记录_' + new Date().toISOString().slice(0,10) + '.json'; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); + } catch (e) { + console.error('导出订阅记录失败:', e); + alert('导出订阅记录失败,请稍后重试'); + } +} + // 主函数:处理用户输入并显示结果 async function consultationFunction() { const userInput = document.getElementById('consultation-input').value; @@ -366,7 +198,7 @@ async function consultationFunction() { } try { - const newsResults = await fetchLegalNews(userInput); + newsResults = await fetchLegalNews(userInput); if (newsResults.length > 0) { displayNewsResults(newsResults); } else { @@ -385,13 +217,25 @@ document.getElementById('consultation-input').addEventListener('keyup', function } }); -// 初始化结果容器 +// 初始化结果容器和订阅列表 document.addEventListener('DOMContentLoaded', function() { if (!document.getElementById('result-container')) { const resultContainer = document.createElement('div'); resultContainer.id = 'result-container'; document.body.appendChild(resultContainer); } + + // 从localStorage加载订阅列表 + try { + const newsSubscription = JSON.parse(localStorage.getItem('newsSubscription') || '[]'); + subscribedNewsList = newsSubscription.map(record => record.news); + } catch (e) { + console.error('加载订阅记录失败:', e); + subscribedNewsList = []; + } + + // 初始化订阅计数 + updateSubscriptionCount(); }); // 添加必要的CSS样式 diff --git a/src/智能法律顾问/js/python/build_qa_database.py b/src/智能法律顾问/js/python/build_qa_database.py new file mode 100644 index 0000000..39aa461 --- /dev/null +++ b/src/智能法律顾问/js/python/build_qa_database.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# File: insert_es.py +# Author: lhy +# Date: 18-10-10 + +import os +import time + +import json +from elasticsearch import Elasticsearch +from elasticsearch.helpers import bulk +import pymongo + +class ProcessIntoES: + def __init__(self): + self._index = "crime_data" + self.es = Elasticsearch([{"host": "127.0.0.1", "port": 9200}]) + self.doc_type = "crime" + cur = '/'.join(os.path.abspath(__file__).split('/')[:-1]) + self.music_file = os.path.join(cur, 'qa_corpus.json') + + '''创建ES索引,确定分词类型''' + def create_mapping(self): + node_mappings = { + "mappings": { + self.doc_type: { # type + "properties": { + "question": { # field: 问题 + "type": "text", # lxw NOTE: cannot be string + "analyzer": "ik_max_word", + "search_analyzer": "ik_smart", + "index": "true" # The index option controls whether field values are indexed. + }, + "answers": { # field: 问题 + "type": "text", # lxw NOTE: cannot be string + "analyzer": "ik_max_word", + "search_analyzer": "ik_smart", + "index": "true" # The index option controls whether field values are indexed. + }, + } + } + } + } + if not self.es.indices.exists(index=self._index): + self.es.indices.create(index=self._index, body=node_mappings) + print("Create {} mapping successfully.".format(self._index)) + else: + print("index({}) already exists.".format(self._index)) + + '''批量插入数据''' + def insert_data_bulk(self, action_list): + success, _ = bulk(self.es, action_list, index=self._index, raise_on_error=True) + print("Performed {0} actions. _: {1}".format(success, _)) + + +'''初始化ES,将数据插入到ES数据库当中''' +def init_ES(): + pie = ProcessIntoES() + # 创建ES的index + pie.create_mapping() + start_time = time.time() + index = 0 + count = 0 + action_list = [] + BULK_COUNT = 1000 # 每BULK_COUNT个句子一起插入到ES中 + + for line in open(pie.music_file): + if not line: + continue + item = json.loads(line) + index += 1 + action = { + "_index": pie._index, + "_type": pie.doc_type, + "_source": { + "question": item['question'], + "answers": '\n'.join(item['answers']), + } + } + action_list.append(action) + if index > BULK_COUNT: + pie.insert_data_bulk(action_list=action_list) + index = 0 + count += 1 + print(count) + action_list = [] + end_time = time.time() + + print("Time Cost:{0}".format(end_time - start_time)) + + +if __name__ == "__main__": + # 将数据库插入到elasticsearch当中 + # init_ES() + # 按照标题进行查询 + question = '我老公要起诉离婚 我不想离婚怎么办' + diff --git a/src/智能法律顾问/js/python/crime_classify.py b/src/智能法律顾问/js/python/crime_classify.py new file mode 100644 index 0000000..1068d37 --- /dev/null +++ b/src/智能法律顾问/js/python/crime_classify.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# File: crime_classify.py.py +# Author: lhy +# Date: 18-11-11 + + +import os +import numpy as np +import jieba.posseg as pseg +from sklearn.externals import joblib + +class CrimeClassify(object): + def __init__(self): + cur = '/'.join(os.path.abspath(__file__).split('/')[:-1]) + crime_file = os.path.join(cur, 'dict/crime.txt') + self.label_dict = self.build_crime_dict(crime_file) + self.id_dict = {j:i for i,j in self.label_dict.items()} + self.embedding_path = os.path.join(cur, 'embedding/word_vec_300.bin') + self.embdding_dict = self.load_embedding(self.embedding_path) + self.embedding_size = 300 + self.model_path = 'model/crime_predict.model' + return + + '''构建罪名词类型''' + def build_crime_dict(self, crimefile): + label_dict = {} + i = 0 + for line in open(crimefile): + crime = line.strip() + if not crime: + continue + label_dict[crime] = i + i +=1 + return label_dict + + '''加载词向量''' + def load_embedding(self, embedding_path): + embedding_dict = {} + count = 0 + for line in open(embedding_path): + line = line.strip().split(' ') + if len(line) < 300: + continue + wd = line[0] + vector = np.array([float(i) for i in line[1:]]) + embedding_dict[wd] = vector + count += 1 + if count%10000 == 0: + print(count, 'loaded') + print('loaded %s word embedding, finished'%count, ) + return embedding_dict + + '''对文本进行分词处理''' + def seg_sent(self, s): + wds = [i.word for i in pseg.cut(s) if i.flag[0] not in ['x', 'u', 'c', 'p', 'm', 't']] + return wds + + '''基于wordvector,通过lookup table的方式找到句子的wordvector的表示''' + def rep_sentencevector(self, sentence, flag='seg'): + if flag == 'seg': + word_list = [i for i in sentence.split(' ') if i] + else: + word_list = self.seg_sent(sentence) + embedding = np.zeros(self.embedding_size) + sent_len = 0 + for index, wd in enumerate(word_list): + if wd in self.embdding_dict: + embedding += self.embdding_dict.get(wd) + sent_len += 1 + else: + continue + return embedding/sent_len + + '''对数据进行onehot映射操作''' + def label_onehot(self, label): + one_hot = [0]*len(self.label_dict) + one_hot[int(label)] = 1 + return one_hot + + '''使用svm模型进行预测''' + def predict(self, sent): + model = joblib.load(self.model_path) + represent_sent = self.rep_sentencevector(sent, flag='noseg') + text_vector = np.array(represent_sent).reshape(1, -1) + res = model.predict(text_vector)[0] + label = self.id_dict.get(res) + return label + + + + +def test(): + handler = CrimeClassify() + while(1): + sent = input('crime desc:') + label = handler.predict(sent) + print('crime label:', label) + +if __name__ == '__main__': + test() diff --git a/src/智能法律顾问/js/python/crime_classify_train.py b/src/智能法律顾问/js/python/crime_classify_train.py new file mode 100644 index 0000000..f63b260 --- /dev/null +++ b/src/智能法律顾问/js/python/crime_classify_train.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# File: crime_classify.py +# Author: lhy +# Date: 18-11-10 + +import os +import numpy as np +from sklearn.svm import SVC, LinearSVC +import jieba.posseg as pseg +from collections import Counter +from sklearn.externals import joblib + +class CrimeClassify(object): + def __init__(self): + cur = '/'.join(os.path.abspath(__file__).split('/')[:-1]) + crime_file = os.path.join(cur, 'crime.txt') + self.label_dict = self.build_crime_dict(crime_file) + self.id_dict = {j:i for i,j in self.label_dict.items()} + self.train_file = os.path.join(cur, 'crime_train_all.txt') + self.embedding_path = os.path.join(cur, 'embedding/word_vec_300.bin') + self.embdding_dict = self.load_embedding(self.embedding_path) + self.embedding_size = 300 + self.model_path = 'crime_predict_svm_all.model' + return + + '''构建罪名词类型''' + def build_crime_dict(self, crimefile): + label_dict = {} + i = 0 + for line in open(crimefile): + crime = line.strip() + if not crime: + continue + label_dict[crime] = i + i +=1 + return label_dict + + '''加载词向量''' + def load_embedding(self, embedding_path): + embedding_dict = {} + count = 0 + for line in open(embedding_path): + line = line.strip().split(' ') + if len(line) < 300: + continue + wd = line[0] + vector = np.array([float(i) for i in line[1:]]) + embedding_dict[wd] = vector + count += 1 + if count%10000 == 0: + print(count, 'loaded') + print('loaded %s word embedding, finished'%count, ) + return embedding_dict + + '''对文本进行分词处理''' + def seg_sent(self, s): + wds = [i.word for i in pseg.cut(s) if i.flag[0] not in ['x', 'u', 'c', 'p', 'm', 't']] + return wds + + '''基于wordvector,通过lookup table的方式找到句子的wordvector的表示''' + def rep_sentencevector(self, sentence, flag='seg'): + if flag == 'seg': + word_list = [i for i in sentence.split(' ') if i] + else: + word_list = self.seg_sent(sentence) + embedding = np.zeros(self.embedding_size) + sent_len = 0 + for index, wd in enumerate(word_list): + if wd in self.embdding_dict: + embedding += self.embdding_dict.get(wd) + sent_len += 1 + else: + continue + return embedding/sent_len + + '''对数据进行onehot映射操作''' + def label_onehot(self, label): + one_hot = [0]*len(self.label_dict) + one_hot[int(label)] = 1 + return one_hot + + '''加载数据集''' + def load_traindata(self): + train_X = [] + train_Y = [] + count = 0 + for line in open(self.train_file): + line = line.strip().strip().split('\t') + if len(line) < 2: + continue + count += 1 + # if count > 1000: + # break + sent = line[1] + label_id = int(line[0]) + sent_vector = self.rep_sentencevector(sent, flag='seg') + train_X.append(sent_vector) + train_Y.append(label_id) + if count % 10000 == 0: + print('loaded %s lines'%count) + return np.array(train_X), np.array(train_Y) + + '''使用SVM进行分类''' + def train_classifer(self): + x_train, y_train = self.load_traindata() + model = LinearSVC() + model.fit(x_train, y_train) + joblib.dump(model, self.model_path) + y_predict = model.predict(x_train) + all = len(y_predict) + right = 0 + for i in range(len(y_train)): + y = y_train[i] + y_pred = y_predict[i] + if y_pred == y: + right += 1 + print('precision:%s/%s=%s'%(right, all, right/all)) + + '''使用svm模型进行预测''' + def predict(self, sent): + model = joblib.load(self.model_path) + represent_sent = self.rep_sentencevector(sent, flag='noseg') + text_vector = np.array(represent_sent).reshape(1, -1) + res = model.predict(text_vector)[0] + label = self.id_dict.get(res) + return label + + + '''检查测试合准确率''' + def check_precision(self): + model = joblib.load(self.model_path) + x_train, y_train = self.load_traindata() + y_predict = model.predict(x_train) + all = len(y_predict) + right = 0 + for i in range(len(y_train)): + y = y_train[i] + y_pred = y_predict[i] + if y_pred == y: + right += 1 + print('precision:%s/%s=%s'%(right, all, right/all)) + # precision:170231 / 204231 = 0.83352184536138 + # precision:2650780 / 2880306 = 0.9203119390786951 + + +def test(): + handler = CrimeClassify() + # handler.train_classifer() + while(1): + sent = input('enter an sent to search:') + label = handler.predict(sent) + print(label) + +def build_data(): + label_dict = {} + i = 0 + for line in open('crime.txt'): + crime = line.strip() + if not crime: + continue + label_dict[crime] = i + i += 1 + + f = open('crime_train_all.txt', 'w+') + count = 0 + for line in open('accu_train.txt'): + line = line.strip().split('###') + if len(line) < 3: + continue + crime = line[1].split(';')[0] + sent = line[-1] + label = label_dict.get(crime) + f.write(str(label) + '\t' + sent + '\n') + count += 1 + print(count) + f.close() + + +if __name__ == '__main__': + test() + #build_data() + #handler = CrimeClassify() + #handler.check_precision() diff --git a/src/智能法律顾问/js/python/crime_qa.py b/src/智能法律顾问/js/python/crime_qa.py new file mode 100644 index 0000000..58b2e4f --- /dev/null +++ b/src/智能法律顾问/js/python/crime_qa.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# File: crime_qa_server.py +# Author: lhy +# Date: 18-11-10 + +import os +import time +import json +from elasticsearch import Elasticsearch +import numpy as np +import jieba.posseg as pseg + +class CrimeQA: + def __init__(self): + self._index = "crime_data" + self.es = Elasticsearch([{"host": "127.0.0.1", "port": 9200}]) + self.doc_type = "crime" + cur = '/'.join(os.path.abspath(__file__).split('/')[:-1]) + self.embedding_path = os.path.join(cur, 'embedding/word_vec_300.bin') + self.embdding_dict = self.load_embedding(self.embedding_path) + self.embedding_size = 300 + self.min_score = 0.4 + self.min_sim = 0.8 + + '''根据question进行事件的匹配查询''' + def search_specific(self, value, key="question"): + query_body = { + "query": { + "match": { + key: value, + } + } + } + searched = self.es.search(index=self._index, doc_type=self.doc_type, body=query_body, size=20) + # 输出查询到的结果 + return searched["hits"]["hits"] + + '''基于ES的问题查询''' + def search_es(self, question): + answers = [] + res = self.search_specific(question) + for hit in res: + answer_dict = {} + answer_dict['score'] = hit['_score'] + answer_dict['sim_question'] = hit['_source']['question'] + answer_dict['answers'] = hit['_source']['answers'].split('\n') + answers.append(answer_dict) + return answers + + + '''加载词向量''' + def load_embedding(self, embedding_path): + embedding_dict = {} + count = 0 + for line in open(embedding_path): + line = line.strip().split(' ') + if len(line) < 300: + continue + wd = line[0] + vector = np.array([float(i) for i in line[1:]]) + embedding_dict[wd] = vector + count += 1 + if count%10000 == 0: + print(count, 'loaded') + print('loaded %s word embedding, finished'%count, ) + return embedding_dict + + + '''对文本进行分词处理''' + def seg_sent(self, s): + wds = [i.word for i in pseg.cut(s) if i.flag[0] not in ['x', 'u', 'c', 'p', 'm', 't']] + return wds + + '''基于wordvector,通过lookup table的方式找到句子的wordvector的表示''' + def rep_sentencevector(self, sentence, flag='seg'): + if flag == 'seg': + word_list = [i for i in sentence.split(' ') if i] + else: + word_list = self.seg_sent(sentence) + embedding = np.zeros(self.embedding_size) + sent_len = 0 + for index, wd in enumerate(word_list): + if wd in self.embdding_dict: + embedding += self.embdding_dict.get(wd) + sent_len += 1 + else: + continue + return embedding/sent_len + + + '''计算问句与库中问句的相似度,对候选结果加以二次筛选''' + def similarity_cosine(self, vector1, vector2): + cos1 = np.sum(vector1*vector2) + cos21 = np.sqrt(sum(vector1**2)) + cos22 = np.sqrt(sum(vector2**2)) + similarity = cos1/float(cos21*cos22) + if similarity == 'nan': + return 0 + else: + return similarity + + '''问答主函数''' + def search_main(self, question): + candi_answers = self.search_es(question) + question_vector = self.rep_sentencevector(question,flag='noseg') + answer_dict = {} + for indx, candi in enumerate(candi_answers): + candi_question = candi['sim_question'] + score = candi['score']/100 + candi_vector = self.rep_sentencevector(candi_question, flag='noseg') + sim = self.similarity_cosine(question_vector, candi_vector) + if sim < self.min_sim: + continue + final_score = (score + sim)/2 + if final_score < self.min_score: + continue + answer_dict[indx] = final_score + if answer_dict: + answer_dict = sorted(answer_dict.items(), key=lambda asd:asd[1], reverse=True) + final_answer = candi_answers[answer_dict[0][0]]['answers'] + else: + final_answer = '您好,对于此类问题,您可以咨询公安部门' + # + # for i in answer_dict: + # answer_indx = i[0] + # score = i[1] + # print(i, score, candi_answers[answer_indx]) + # print('******'*6) + return final_answer + + +if __name__ == "__main__": + handler = CrimeQA() + while(1): + question = input('question:') + final_answer = handler.search_main(question) + print('answers:', final_answer) + diff --git a/src/智能法律顾问/js/python/manage.py b/src/智能法律顾问/js/python/manage.py new file mode 100644 index 0000000..60eb248 --- /dev/null +++ b/src/智能法律顾问/js/python/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'chat.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/src/智能法律顾问/js/python/question_classify.py b/src/智能法律顾问/js/python/question_classify.py new file mode 100644 index 0000000..0c1ac1f --- /dev/null +++ b/src/智能法律顾问/js/python/question_classify.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# File: question_classify.py +# Author: lhy +# Date: 18-11-11 + + +import os +import numpy as np +import jieba.posseg as pseg +from keras.models import Sequential, load_model +from keras.layers import Conv1D, GlobalAveragePooling1D, MaxPooling1D, Dense, Dropout, LSTM, Bidirectional + + +class QuestionClassify(object): + def __init__(self): + self.label_dict = { + 0: "婚姻家庭", + 1: "劳动纠纷", + 2: "交通事故", + 3: "债权债务", + 4: "刑事辩护", + 5: "合同纠纷", + 6: "房产纠纷", + 7: "侵权", + 8: "公司法", + 9: "医疗纠纷", + 10: "拆迁安置", + 11: "行政诉讼", + 12: "建设工程" + } + cur = '/'.join(os.path.abspath(__file__).split('/')[:-1]) + self.embedding_path = os.path.join(cur, 'embedding/word_vec_300.bin') + self.embdding_dict = self.load_embedding(self.embedding_path) + self.max_length = 60 + self.embedding_size = 300 + self.lstm_modelpath = 'model/lstm_question_classify.h5' + self.cnn_modelpath = 'model/cnn_question_classify.h5' + return + + '''加载词向量''' + def load_embedding(self, embedding_path): + embedding_dict = {} + count = 0 + for line in open(embedding_path): + line = line.strip().split(' ') + if len(line) < 300: + continue + wd = line[0] + vector = np.array([float(i) for i in line[1:]]) + embedding_dict[wd] = vector + count += 1 + if count % 10000 == 0: + print(count, 'loaded') + print('loaded %s word embedding, finished' % count, ) + return embedding_dict + + '''对文本进行分词处理''' + + def seg_sent(self, s): + wds = [i.word for i in pseg.cut(s) if i.flag[0] not in ['w', 'x']] + return wds + + '''基于wordvector,通过lookup table的方式找到句子的wordvector的表示''' + + def rep_sentencevector(self, sentence): + word_list = self.seg_sent(sentence)[:self.max_length] + embedding_matrix = np.zeros((self.max_length, self.embedding_size)) + for index, wd in enumerate(word_list): + if wd in self.embdding_dict: + embedding_matrix[index] = self.embdding_dict.get(wd) + else: + continue + len_sent = len(word_list) + embedding_matrix = self.modify_sentencevector(embedding_matrix, len_sent) + + return embedding_matrix + + '''对于OOV词,通过左右词的词向量作平均,作为词向量表示''' + + def modify_sentencevector(self, embedding_matrix, len_sent): + context_window = 2 + for indx, vec in enumerate(embedding_matrix): + left = indx - context_window + right = indx + context_window + if left < 0: + left = 0 + if right > len(embedding_matrix) - 1: + right = -2 + context = embedding_matrix[left:right + 1] + if vec.tolist() == [0] * 300 and indx < len_sent: + context_vector = context.mean(axis=0) + embedding_matrix[indx] = context_vector + + return embedding_matrix + + '''对数据进行onehot映射操作''' + + def label_onehot(self, label): + one_hot = [0] * len(self.label_dict) + one_hot[int(label)] = 1 + return one_hot + + + '''构造CNN网络模型''' + def build_cnn_model(self): + model = Sequential() + model.add(Conv1D(64, 3, activation='relu', input_shape=(self.max_length, self.embedding_size))) + model.add(Conv1D(64, 3, activation='relu')) + model.add(MaxPooling1D(3)) + model.add(Conv1D(128, 3, activation='relu')) + model.add(Conv1D(128, 3, activation='relu')) + model.add(GlobalAveragePooling1D()) + model.add(Dropout(0.5)) + model.add(Dense(13, activation='softmax')) + model.compile(loss='categorical_crossentropy', + optimizer='rmsprop', + metrics=['accuracy']) + model.summary() + return model + + '''构造LSTM网络''' + def build_lstm_model(self): + model = Sequential() + model.add(LSTM(32, return_sequences=True, input_shape=( + self.max_length, self.embedding_size))) # returns a sequence of vectors of dimension 32 + model.add(LSTM(32, return_sequences=True)) # returns a sequence of vectors of dimension 32 + model.add(LSTM(32)) # return a single vector of dimension 32 + model.add(Dense(13, activation='softmax')) + model.compile(loss='categorical_crossentropy', + optimizer='rmsprop', + metrics=['accuracy']) + + return model + + '''问题分类''' + def predict(self, sent): + model = load_model(self.cnn_modelpath) + sentence_vector = np.array([self.rep_sentencevector(sent)]) + res = model.predict(sentence_vector)[0].tolist() + prob = max(res) + label = self.label_dict.get(res.index(prob)) + return label, prob + +if __name__ == '__main__': + handler = QuestionClassify() + while (1): + sent = input('question desc:') + label, prob = handler.predict(sent) + print('question_type:', label, prob) diff --git a/src/智能法律顾问/js/python/question_classify_train.py b/src/智能法律顾问/js/python/question_classify_train.py new file mode 100644 index 0000000..f8d9292 --- /dev/null +++ b/src/智能法律顾问/js/python/question_classify_train.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# File: question_classify.py +# Author: lhy +# Date: 18-11-10 + +import os +import numpy as np +import jieba.posseg as pseg +from keras.models import Sequential, load_model +from keras.layers import Conv1D, GlobalAveragePooling1D, MaxPooling1D, Dense, Dropout, LSTM, Bidirectional + +class QuestionClassify(object): + def __init__(self): + self.label_dict = { + 0:"婚姻家庭", + 1:"劳动纠纷", + 2:"交通事故", + 3:"债权债务", + 4:"刑事辩护", + 5:"合同纠纷", + 6:"房产纠纷", + 7:"侵权", + 8:"公司法", + 9:"医疗纠纷", + 10:"拆迁安置", + 11:"行政诉讼", + 12:"建设工程" + } + cur = '/'.join(os.path.abspath(__file__).split('/')[:-1]) + self.train_file = os.path.join(cur, 'question_train.txt') + self.embedding_path = os.path.join(cur, 'word_vec_300.bin') + self.embdding_dict = self.load_embedding(self.embedding_path) + self.max_length = 60 + self.embedding_size = 300 + self.lstm_modelpath = 'model/lstm_question_classify.h5' + self.cnn_modelpath = 'model/cnn_question_classify.h5' + return + + '''加载词向量''' + def load_embedding(self, embedding_path): + embedding_dict = {} + count = 0 + for line in open(embedding_path): + line = line.strip().split(' ') + if len(line) < 300: + continue + wd = line[0] + vector = np.array([float(i) for i in line[1:]]) + embedding_dict[wd] = vector + count += 1 + if count%10000 == 0: + print(count, 'loaded') + print('loaded %s word embedding, finished'%count, ) + return embedding_dict + + '''对文本进行分词处理''' + def seg_sent(self, s): + wds = [i.word for i in pseg.cut(s) if i.flag[0] not in ['w', 'x']] + return wds + + '''基于wordvector,通过lookup table的方式找到句子的wordvector的表示''' + def rep_sentencevector(self, sentence): + word_list = self.seg_sent(sentence)[:self.max_length] + embedding_matrix = np.zeros((self.max_length, self.embedding_size)) + for index, wd in enumerate(word_list): + if wd in self.embdding_dict: + embedding_matrix[index] = self.embdding_dict.get(wd) + else: + continue + len_sent = len(word_list) + embedding_matrix = self.modify_sentencevector(embedding_matrix, len_sent) + + return embedding_matrix + + '''对于OOV词,通过左右词的词向量作平均,作为词向量表示''' + def modify_sentencevector(self, embedding_matrix, len_sent): + context_window = 2 + for indx, vec in enumerate(embedding_matrix): + left = indx-context_window + right = indx+context_window + if left < 0: + left = 0 + if right > len(embedding_matrix)-1: + right = -2 + context = embedding_matrix[left:right+1] + if vec.tolist() == [0]*300 and indx < len_sent: + context_vector = context.mean(axis=0) + embedding_matrix[indx] = context_vector + + return embedding_matrix + + '''对数据进行onehot映射操作''' + def label_onehot(self, label): + one_hot = [0]*len(self.label_dict) + one_hot[int(label)] = 1 + return one_hot + + '''加载数据集''' + def load_traindata(self): + train_X = [] + train_Y = [] + count = 0 + for line in open(self.train_file): + + line = line.strip().strip().split('\t') + if len(line) < 2: + continue + count += 1 + sent = line[0] + label = line[1] + sent_vector = self.rep_sentencevector(sent) + label_vector = self.label_onehot(label) + train_X.append(sent_vector) + train_Y.append(label_vector) + + if count % 10000 == 0: + print('loaded %s lines'%count) + + return np.array(train_X), np.array(train_Y) + + '''构造CNN网络模型''' + def build_cnn_model(self): + model = Sequential() + model.add(Conv1D(64, 3, activation='relu', input_shape=(self.max_length, self.embedding_size))) + model.add(Conv1D(64, 3, activation='relu')) + model.add(MaxPooling1D(3)) + model.add(Conv1D(128, 3, activation='relu')) + model.add(Conv1D(128, 3, activation='relu')) + model.add(GlobalAveragePooling1D()) + model.add(Dropout(0.5)) + model.add(Dense(13, activation='softmax')) + model.compile(loss='categorical_crossentropy', + optimizer='rmsprop', + metrics=['accuracy']) + model.summary() + return model + + '''构造LSTM网络''' + def build_lstm_model(self): + model = Sequential() + model.add(LSTM(32, return_sequences=True, input_shape=(self.max_length, self.embedding_size))) # returns a sequence of vectors of dimension 32 + model.add(LSTM(32, return_sequences=True)) # returns a sequence of vectors of dimension 32 + model.add(LSTM(32)) # return a single vector of dimension 32 + model.add(Dense(13, activation='softmax')) + model.compile(loss='categorical_crossentropy', + optimizer='rmsprop', + metrics=['accuracy']) + + return model + + '''训练CNN模型''' + def train_cnn(self): + X_train, Y_train, X_test, Y_test = self.split_trainset() + model = self.build_cnn_model() + model.fit(X_train, Y_train, batch_size=100, epochs=20, validation_data=(X_test, Y_test)) + model.save(self.cnn_modelpath) + + '''训练CNN模型''' + def train_lstm(self): + X_train, Y_train, X_test, Y_test = self.split_trainset() + model = self.build_lstm_model() + model.fit(X_train, Y_train, batch_size=100, epochs=50, validation_data=(X_test, Y_test)) + model.save(self.lstm_modelpath) + + '''划分数据集,按一定比例划分训练集和测试集''' + def split_trainset(self): + X, Y = self.load_traindata() + split_rate = 0.8 + indx = int(len(X)*split_rate) + X_train = X[:indx] + Y_train = Y[:indx] + X_test = X[indx:] + Y_test = Y[indx:] + return X_train, Y_train, X_test, Y_test + + +if __name__ == '__main__': + handler = QuestionClassify() + handler.train_cnn() + handler.train_lstm() diff --git a/src/智能法律顾问/js/termscript.js b/src/智能法律顾问/js/termscript.js index b428ef6..822e6a8 100644 --- a/src/智能法律顾问/js/termscript.js +++ b/src/智能法律顾问/js/termscript.js @@ -1,8 +1,85 @@ +// 全局变量存储搜索记录 +let globalSearchHistory = []; + +// 初始化搜索历史记录 +function initSearchHistory() { + if(!localStorage.getItem('searchHistory')) { + localStorage.setItem('searchHistory', JSON.stringify([])); + } + globalSearchHistory = JSON.parse(localStorage.getItem('searchHistory')); +} + +// 添加搜索记录 +function addSearchRecord(term) { + const newSearch = { + term: term, + timestamp: new Date().toISOString(), + result: '', // 存储查询结果 + matchType: '', // 存储匹配类型(完全匹配/相似匹配等) + similarTerms: [] // 存储相似术语列表 + }; + + globalSearchHistory.push(newSearch); + + // 如果历史记录超过100条,删除最早的记录 + if(globalSearchHistory.length > 100) { + globalSearchHistory.shift(); + } + + // 保存更新后的历史记录 + localStorage.setItem('searchHistory', JSON.stringify(globalSearchHistory)); +} + +// 获取搜索历史 +function getSearchHistory() { + return globalSearchHistory; +} + +// 导出搜索历史为JSON +function exportSearchHistory() { + const historyJson = JSON.stringify(globalSearchHistory, null, 2); + const blob = new Blob([historyJson], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + + const a = document.createElement('a'); + a.href = url; + a.download = 'legal_term_search_history.json'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); +} + +// 清空搜索历史 +function clearSearchHistory() { + globalSearchHistory = []; + localStorage.setItem('searchHistory', JSON.stringify([])); +} + +// 更新搜索记录的结果 +function updateSearchRecord(term, result, matchType, similarTerms) { + const lastRecord = globalSearchHistory[globalSearchHistory.length - 1]; + if(lastRecord && lastRecord.term === term) { + lastRecord.result = result; + lastRecord.matchType = matchType; + lastRecord.similarTerms = similarTerms; + localStorage.setItem('searchHistory', JSON.stringify(globalSearchHistory)); + } +} + function consultationFunction() { var userInput = document.getElementById('consultation-input').value; + + // 初始化搜索历史 + initSearchHistory(); + + // 添加新的搜索记录 + addSearchRecord(userInput); + alert("您咨询的问题是: " + userInput); // 这里可以添加更多的逻辑来处理用户的咨询 } + document.addEventListener('DOMContentLoaded', function() { const createSparkle = (x, y) => { const sparkle = document.createElement('div'); @@ -238,11 +315,11 @@ function consultationFunction() { var resultBox = document.getElementById('result-box'); var resultTextarea = document.getElementById('result-textarea'); - // 记录用户输入历史 - if (!window.searchHistory) { - window.searchHistory = []; - } - window.searchHistory.push(searchTerm); + // 初始化搜索历史 + initSearchHistory(); + + // 添加新的搜索记录 + addSearchRecord(searchTerm); // 获取法律术语数据和关键词权重数据 Promise.all([ @@ -250,38 +327,53 @@ function consultationFunction() { fetch('./json/legalterm/TermKEYS.json').then(response => response.json()) ]).then(([legalTermsData, keywordsData]) => { const termData = legalTermsData.find(term => term.term.toLowerCase() === searchTerm); + let result = ''; + let matchType = ''; + let similarTerms = []; + if (termData) { // 完全匹配,直接输出结果 - resultTextarea.value = `${termData.term}: ${termData.definition}`; + result = `${termData.term}: ${termData.definition}`; + matchType = '完全匹配'; + resultTextarea.value = result; } else { - const historyLength = window.searchHistory.length; - if (historyLength >= 3 && isConsecutiveIdentical(window.searchHistory.slice(-3))) { + const searchHistory = getSearchHistory(); + const historyLength = searchHistory.length; + const recentSearches = searchHistory.slice(-3).map(h => h.term); + + if (historyLength >= 3 && isConsecutiveIdentical(recentSearches)) { // 连续三次及以上输入相同且不存在的词汇 - const topTerms = findSimilarTerms(legalTermsData, keywordsData.keywords, searchTerm, 10); - let message = "未找到完全匹配的术语,为您提供可能相关的十条术语:\n\n"; - topTerms.forEach((term, index) => { - message += `${index + 1}. ${term.term}: ${term.definition}\n\n`; + similarTerms = findSimilarTerms(legalTermsData, keywordsData.keywords, searchTerm, 10); + matchType = '多次尝试相似匹配'; + result = "未找到完全匹配的术语,为您提供可能相关的十条术语:\n\n"; + similarTerms.forEach((term, index) => { + result += `${index + 1}. ${term.term}: ${term.definition}\n\n`; }); - resultTextarea.value = message; - } else if (historyLength >= 2 && searchTerm === window.searchHistory[historyLength - 2]) { + resultTextarea.value = result; + } else if (historyLength >= 2 && searchTerm === searchHistory[historyLength - 2].term) { // 连续两次输入相同且不存在的词汇 - const similarTerms = findSimilarTerms(legalTermsData, keywordsData.keywords, searchTerm, 4); + similarTerms = findSimilarTerms(legalTermsData, keywordsData.keywords, searchTerm, 4); + matchType = '二次尝试相似匹配'; if (similarTerms.length > 0) { - let message = `最匹配的术语:\n\n`; - message += `${similarTerms[0].term}: ${similarTerms[0].definition}\n\n`; - message += "其他可能相关的术语:\n"; + result = `最匹配的术语:\n\n${similarTerms[0].term}: ${similarTerms[0].definition}\n\n其他可能相关的术语:\n`; for (let i = 1; i < similarTerms.length; i++) { - message += `${i}. ${similarTerms[i].term}: ${similarTerms[i].definition}\n\n`; + result += `${i}. ${similarTerms[i].term}: ${similarTerms[i].definition}\n\n`; } - resultTextarea.value = message; + resultTextarea.value = result; } else { - resultTextarea.value = `未找到"${searchTerm}"相关的术语。请尝试使用其他关键词。`; + result = `未找到"${searchTerm}"相关的术语。请尝试使用其他关键词。`; + resultTextarea.value = result; } } else { // 首次输入不存在的词汇 - resultTextarea.value = `未找到"${searchTerm}"。请尝试更换其他词汇。`; + matchType = '未匹配'; + result = `未找到"${searchTerm}"。请尝试更换其他词汇。`; + resultTextarea.value = result; } } + + // 更新搜索记录的结果 + updateSearchRecord(searchTerm, result, matchType, similarTerms); showResultBox(resultBox); }).catch(error => { console.error('Error:', error); diff --git a/src/智能法律顾问/json/jsonl_to_json.py b/src/智能法律顾问/json/json_python/jsonl_to_json.py similarity index 100% rename from src/智能法律顾问/json/jsonl_to_json.py rename to src/智能法律顾问/json/json_python/jsonl_to_json.py diff --git a/src/智能法律顾问/login.html b/src/智能法律顾问/login.html deleted file mode 100644 index e69de29..0000000 diff --git a/src/智能法律顾问/news-subscription.html b/src/智能法律顾问/news-subscription.html index 85694b0..51c0dfc 100644 --- a/src/智能法律顾问/news-subscription.html +++ b/src/智能法律顾问/news-subscription.html @@ -104,6 +104,12 @@ display: flex; justify-content: space-between; align-items: center; + position: relative; + color: red; + transition: color 0.3s ease; + } + .subscribed-news-item:hover { + color: black; } .delete-btn { background-color: #d9534f; @@ -112,12 +118,356 @@ padding: 5px 10px; border-radius: 3px; cursor: pointer; + transition: transform 0.3s ease; + } + .delete-btn:hover { + transform: scale(1.1); + } + .delete-btn:active { + animation: shatter 0.5s forwards; + } + @keyframes shatter { + 0% { + transform: scale(1); + } + 100% { + transform: scale(0); + opacity: 0; + } + } + /* 额外的高级样式 */ + .news-box { + background: linear-gradient(145deg, #f8f8f8, #ffffff); + border: 1px solid #e0e0e0; + } + .news-box:hover { + background: linear-gradient(145deg, #ffffff, #f8f8f8); + } + .news-box h3 { + font-family: 'Georgia', serif; + letter-spacing: 1px; + } + .news-box a { + font-weight: bold; + text-transform: uppercase; + } + .subscribe-btn { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + } + .subscribe-btn:hover { + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2); + } + .subscription-area { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + } + .subscription-list { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + } + .subscribed-news-item { + background: linear-gradient(145deg, #f8f8f8, #ffffff); + border: 1px solid #e0e0e0; + } + .subscribed-news-item:hover { + background: linear-gradient(145deg, #ffffff, #f8f8f8); + } + .delete-btn { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + } + .delete-btn:hover { + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2); + } + /* 额外的高级样式 */ + .news-box { + background: linear-gradient(145deg, #f8f8f8, #ffffff); + border: 1px solid #e0e0e0; + } + .news-box:hover { + background: linear-gradient(145deg, #ffffff, #f8f8f8); + } + .news-box h3 { + font-family: 'Georgia', serif; + letter-spacing: 1px; + } + .news-box a { + font-weight: bold; + text-transform: uppercase; + } + .subscribe-btn { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + } + .subscribe-btn:hover { + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2); + } + .subscription-area { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + } + .subscription-list { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + } + .subscribed-news-item { + background: linear-gradient(145deg, #f8f8f8, #ffffff); + border: 1px solid #e0e0e0; + } + .subscribed-news-item:hover { + background: linear-gradient(145deg, #ffffff, #f8f8f8); + } + .delete-btn { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + } + .delete-btn:hover { + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2); + } + /* 额外的高级样式 */ + .news-box { + background: linear-gradient(145deg, #f8f8f8, #ffffff); + border: 1px solid #e0e0e0; + } + .news-box:hover { + background: linear-gradient(145deg, #ffffff, #f8f8f8); + } + .news-box h3 { + font-family: 'Georgia', serif; + letter-spacing: 1px; + } + .news-box a { + font-weight: bold; + text-transform: uppercase; + } + .subscribe-btn { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + } + .subscribe-btn:hover { + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2); + } + .subscription-area { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + } + .subscription-list { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + } + .subscribed-news-item { + background: linear-gradient(145deg, #f8f8f8, #ffffff); + border: 1px solid #e0e0e0; + } + .subscribed-news-item:hover { + background: linear-gradient(145deg, #ffffff, #f8f8f8); + } + .delete-btn { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); } + .delete-btn:hover { + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2); + } + /* ... 现有样式保持不变 ... */ + +/* 订阅区域的高级样式 */ +.subscription-area { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.3); + padding: 12px 20px; + border-radius: 15px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; +} + +.subscription-area:hover { + transform: translateY(-2px); + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15); +} + +.subscription-area i { + font-size: 1.2em; + color: #d9534f; +} + +/* 订阅列表的高级样式 */ +/* 订阅列表的高级样式 */ +.subscription-list { + background: linear-gradient(145deg, #ffffff, #f8f8f8); /* 改为更柔和的渐变背景 */ + backdrop-filter: blur(15px); + border: 1px solid rgba(0, 0, 0, 0.1); /* 微调边框颜色 */ + border-radius: 20px; + box-shadow: 0 15px 45px rgba(0, 0, 0, 0.08); /* 减小阴影强度 */ + padding: 25px; + animation: slideIn 0.3s ease; +} + +.subscription-list h3 { + color: #333; /* 深灰色标题 */ + font-size: 1.2em; + margin-bottom: 20px; + font-weight: 600; + letter-spacing: 0.5px; +} + +/* 订阅项目的高级样式 */ +.subscribed-news-item { + background: #ffffff; /* 纯白背景 */ + border: 1px solid rgba(0, 0, 0, 0.08); + border-radius: 12px; + padding: 15px; + margin-bottom: 15px; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.03); /* 更细腻的阴影 */ + transition: all 0.3s ease; + transform-origin: center; + display: flex; + justify-content: space-between; + align-items: center; +} + +.subscribed-news-item a { + color: #2c3e50; /* 更专业的链接颜色 */ + text-decoration: none; + font-size: 0.95em; + flex: 1; + margin-right: 15px; + transition: color 0.3s ease; +} + +.subscribed-news-item a:hover { + color: #d9534f; /* 保持红色主题 */ +} + +/* 删除按钮的高级样式 */ +.delete-btn { + background: linear-gradient(145deg, #ff5b5b, #d9534f); + border: none; + padding: 8px 15px; + border-radius: 8px; + color: white; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 15px rgba(217, 83, 79, 0.2); +} + +.delete-btn:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(217, 83, 79, 0.3); +} + +/* 破碎动画效果 */ +@keyframes shatter { + 0% { + transform: scale(1); + opacity: 1; + } + 20% { + transform: scale(1.1) rotate(5deg); + } + 40% { + transform: scale(0.9) rotate(-5deg); + } + 60% { + transform: scale(0.8) skewX(15deg); + opacity: 0.8; + } + 80% { + transform: scale(0.5) skewX(-15deg); + opacity: 0.4; + } + 100% { + transform: scale(0) rotate(15deg); + opacity: 0; + } +} + +/* 滑入动画 */ +@keyframes slideIn { + from { + transform: translateY(-20px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +} + +/* 订阅成功的动画效果 */ +@keyframes subscribeSuccess { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.2); + } + 100% { + transform: scale(1); + } +} + +.subscription-count-animation { + animation: subscribeSuccess 0.5s ease; +} + +/* ... existing code ... */ + +/* 超炫粒子效果 */ +.particle { + position: fixed; /* 改为 fixed 确保显示在最上层 */ + pointer-events: none; + z-index: 99999; /* 提高层级确保显示在最上面 */ + width: 10px; + height: 10px; + background: #ff4444; + box-shadow: 0 0 20px 4px rgba(255, 68, 68, 0.8); /* 增强发光效果 */ + clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); /* 菱形粒子 */ +} + +/* 爆炸中心的光效 */ +.explosion-center { + position: fixed; + pointer-events: none; + z-index: 99998; + width: 100px; + height: 100px; + background: radial-gradient(circle, #fff 0%, rgba(255, 68, 68, 0.8) 40%, transparent 70%); + transform: translate(-50%, -50%); + animation: explode-light 0.5s ease-out forwards; +} + +@keyframes explode-light { + 0% { + transform: translate(-50%, -50%) scale(0); + opacity: 1; + } + 100% { + transform: translate(-50%, -50%) scale(3); + opacity: 0; + } +} + +@keyframes particle-explosion { + 0% { + transform: translate(0, 0) scale(1) rotate(0deg); + opacity: 1; + } + 70% { + opacity: 1; + } + 100% { + transform: translate(var(--tx), var(--ty)) scale(0.1) rotate(var(--rotate)); + opacity: 0; + } +} diff --git a/src/智能法律顾问/personalized-learning.html b/src/智能法律顾问/personalized-learning.html index 06995a3..94fd349 100644 --- a/src/智能法律顾问/personalized-learning.html +++ b/src/智能法律顾问/personalized-learning.html @@ -25,9 +25,247 @@ height: auto; margin-top: 10px; } + .file-export-section { + margin: 20px; + padding: 30px; + border: 2px solid #ff4d4d; + border-radius: 15px; + background: linear-gradient(135deg, #fff5f5 0%, #ffffff 100%); + box-shadow: 0 4px 20px rgba(255, 77, 77, 0.15); + transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; + opacity: 0; + transform: translateY(30px); + animation: fadeInUp 1s ease-out forwards; + animation-delay: 0.5s; + } + + @keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + .file-export-section:hover { + transform: translateY(-5px) scale(1.02); + box-shadow: 0 8px 25px rgba(255, 77, 77, 0.25); + } + + .file-export-section::before { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: radial-gradient(circle, rgba(255,77,77,0.1) 0%, rgba(255,255,255,0) 70%); + transform: rotate(45deg); + z-index: 0; + animation: shimmer 3s infinite linear; + } + + @keyframes shimmer { + 0% { + transform: rotate(45deg) translateX(-100%); + } + 100% { + transform: rotate(45deg) translateX(100%); + } + } + + .file-selector { + margin: 20px 0; + display: flex; + flex-wrap: wrap; + gap: 15px; + position: relative; + z-index: 1; + opacity: 0; + animation: fadeIn 0.8s ease-out forwards; + animation-delay: 1s; + } + + @keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + .file-selector label { + display: flex; + align-items: center; + padding: 12px 20px; + background: rgba(255, 255, 255, 0.9); + border: 1px solid #ff4d4d; + border-radius: 25px; + cursor: pointer; + transition: all 0.4s ease; + box-shadow: 0 2px 8px rgba(255, 77, 77, 0.1); + backdrop-filter: blur(5px); + } + + .file-selector label:hover { + background: rgba(255, 77, 77, 0.1); + transform: scale(1.05) rotate(1deg); + } + + .file-selector input[type="checkbox"] { + display: none; + } + + .file-selector label span { + position: relative; + padding-left: 30px; + font-weight: 500; + color: #ff4d4d; + transition: all 0.3s ease; + } + + .file-selector label span:before { + content: ''; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 18px; + height: 18px; + border: 2px solid #ff4d4d; + border-radius: 6px; + transition: all 0.3s ease; + } + + .file-selector input[type="checkbox"]:checked + span:before { + background: #ff4d4d; + transform: translateY(-50%) scale(0.9); + animation: checkmark 0.3s ease-out; + } + + @keyframes checkmark { + 0% { + transform: translateY(-50%) scale(1.2); + } + 50% { + transform: translateY(-50%) scale(0.8); + } + 100% { + transform: translateY(-50%) scale(0.9); + } + } + + .file-selector input[type="checkbox"]:checked + span:after { + content: '✓'; + position: absolute; + left: 4px; + top: 50%; + transform: translateY(-50%); + color: white; + font-size: 14px; + font-weight: bold; + animation: fadeInCheck 0.3s ease-out; + } + + @keyframes fadeInCheck { + from { + opacity: 0; + transform: translateY(-50%) scale(0); + } + to { + opacity: 1; + transform: translateY(-50%) scale(1); + } + } + + .export-btn { + background: linear-gradient(45deg, #ff4d4d, #ff6b6b); + color: white; + padding: 15px 30px; + border: none; + border-radius: 30px; + cursor: pointer; + font-weight: bold; + font-size: 16px; + letter-spacing: 1px; + transition: all 0.4s ease; + box-shadow: 0 4px 15px rgba(255, 77, 77, 0.3); + position: relative; + overflow: hidden; + opacity: 1; /* 修改这里,将初始透明度设为1 */ + } + + .export-btn:hover { + background: linear-gradient(45deg, #ff6b6b, #ff4d4d); + transform: translateY(-3px); + box-shadow: 0 6px 20px rgba(255, 77, 77, 0.4); + } + + .export-btn:active { + transform: translateY(1px); + } + + .export-btn::after { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: radial-gradient(circle, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0) 70%); + transform: rotate(45deg); + transition: all 0.3s ease; + } + + .export-btn:hover::after { + transform: rotate(45deg) translate(50%, 50%); + } + + .popup-menu { + position: fixed; + background: white; + padding: 15px; + border-radius: 12px; + box-shadow: 0 5px 25px rgba(0,0,0,0.2); + z-index: 1000; + opacity: 0; + transform: scale(0.95); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + border: 2px solid #ff4d4d; + } + + .popup-menu.show { + opacity: 1; + transform: scale(1); + } + + .popup-item { + padding: 10px 20px; + cursor: pointer; + border-radius: 8px; + transition: all 0.3s ease; + color: #ff4d4d; + } + + .popup-item:hover { + background: #fff5f5; + } + + .popup-item.selected { + background: #ffe6e6; + color: #ff4d4d; + font-weight: bold; + } +

个性化法律学习计划

@@ -43,6 +281,41 @@
+
+

历史记录导出

+
+ + + + +
+ +
+ + +

© 2024 智能法律服务系统

@@ -50,40 +323,141 @@ \ No newline at end of file