pull/3/head
pyg8ivf7o 4 weeks ago
parent c220d4d3b8
commit d17a270517

@ -1,2 +1,17 @@
# legal_counsel
# 系统简介:
# 当前,法律服务存在效率低下、资源分散、普及率不高等问题,缺乏有效的工具来提升学习和工作效率。
# 为了解决这些问题,我们利用人工智能、大数据等技术,提供一系列智能化法律服务工具,
# 普及法律知识,促进法律知识的学习和研究,帮助公众更好地理解和运用法律,从而推动法律服务行业的现代化和法治社会的建设。
# 该项目针对的主要用户群体包括法律专业人士、学生、研究人员以及普通公众。
# 配置环境:
# VS Code + mySQL
# 成员:
# 220340238 刘明耀
# 220340222 张之阳
# 220340223 开钰昊
# 210340227 梅诗睿
# 220340209 钱 浩

Binary file not shown.

Before

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 KiB

@ -7,6 +7,15 @@
<link rel="stylesheet" href="./css/stylesCase.css">
</head>
<body>
<div class="particle-connect"></div>
<!-- 添加SVG滤镜用于液态效果 -->
<svg style="display: none;">
<filter id="liquid">
<feTurbulence type="fractalNoise" baseFrequency="0.01" numOctaves="3" />
<feDisplacementMap in="SourceGraphic" scale="20" />
</filter>
</svg>
<div id="app">
<header>
<h1>案件匹配</h1>

@ -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;

@ -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; }
}

@ -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; }
}

@ -566,3 +566,286 @@ main {
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;
}

@ -566,3 +566,601 @@ main {
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; }
}

@ -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; }
}

File diff suppressed because it is too large Load Diff

@ -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);
}
// 调整结果框大小的函数

@ -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}"相关的案例。请尝试使用其他关键词。`;
}

@ -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 = '';
}

@ -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.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);
}
// 调整结果框大小的函数

@ -1,210 +1,3 @@
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 = [
// 官方法律新闻源
@ -212,98 +5,12 @@ const legalNewsSources = [
'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样式

@ -0,0 +1,98 @@
#!/usr/bin/env python3
# coding: utf-8
# File: insert_es.py
# Author: lhy<lhy_in_blcu@126.com,https://huangyong.github.io>
# 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 = '我老公要起诉离婚 我不想离婚怎么办'

@ -0,0 +1,101 @@
#!/usr/bin/env python3
# coding: utf-8
# File: crime_classify.py.py
# Author: lhy<lhy_in_blcu@126.com,https://huangyong.github.io>
# 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()

@ -0,0 +1,184 @@
#!/usr/bin/env python3
# coding: utf-8
# File: crime_classify.py
# Author: lhy<lhy_in_blcu@126.com,https://huangyong.github.io>
# 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()

@ -0,0 +1,139 @@
#!/usr/bin/env python3
# coding: utf-8
# File: crime_qa_server.py
# Author: lhy<lhy_in_blcu@126.com,https://huangyong.github.io>
# 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)

@ -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()

@ -0,0 +1,150 @@
#!/usr/bin/env python3
# coding: utf-8
# File: question_classify.py
# Author: lhy<lhy_in_blcu@126.com,https://huangyong.github.io>
# 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)

@ -0,0 +1,181 @@
#!/usr/bin/env python3
# coding: utf-8
# File: question_classify.py
# Author: lhy<lhy_in_blcu@126.com,https://huangyong.github.io>
# 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()

@ -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);

@ -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;
}
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const legalNewsSources = [
'http://www.legaldaily.com.cn/',
/*
'http://www.court.gov.cn/xwzx/',
'http://www.spp.gov.cn/spp/xwfbh/',
'http://www.moj.gov.cn/news/node_330.html',
@ -221,7 +571,7 @@
// 房地产法律新闻
'http://www.mohurd.gov.cn/'
*/
];
let newsResults = [];
@ -305,8 +655,59 @@
const subscribedNews = JSON.parse(localStorage.getItem('subscribedNews') || '[]');
subscribedNews.push(newsResults[index]);
localStorage.setItem('subscribedNews', JSON.stringify(subscribedNews));
alert(`已订阅新闻: ${newsResults[index].title}`);
animateSubscription(index);
updateSubscriptionCount();
// 添加订阅计数动画
const subscriptionCount = document.getElementById('subscriptionCount');
subscriptionCount.classList.add('subscription-count-animation');
setTimeout(() => {
subscriptionCount.classList.remove('subscription-count-animation');
}, 500);
}
// 增强删除动画效果
function deleteSubscribedNews(index) {
const subscribedNews = JSON.parse(localStorage.getItem('subscribedNews') || '[]');
const subscriptionList = document.getElementById('subscriptionList');
const newsItem = subscriptionList.querySelectorAll('.subscribed-news-item')[index];
// 使用简单的淡出动画
newsItem.style.animation = 'fadeOut 0.3s ease forwards';
setTimeout(() => {
subscribedNews.splice(index, 1);
localStorage.setItem('subscribedNews', JSON.stringify(subscribedNews));
showSubscribedNews();
updateSubscriptionCount();
}, 300);
}
function animateSubscription(index) {
const newsBox = document.querySelectorAll('.news-box')[index];
const subscriptionArea = document.querySelector('.subscription-area');
const rect = newsBox.getBoundingClientRect();
const subscriptionRect = subscriptionArea.getBoundingClientRect();
const clone = newsBox.cloneNode(true);
clone.style.position = 'fixed';
clone.style.left = `${rect.left}px`;
clone.style.top = `${rect.top}px`;
clone.style.width = `${rect.width}px`;
clone.style.height = `${rect.height}px`;
clone.style.transition = 'all 0.5s ease-in-out';
document.body.appendChild(clone);
setTimeout(() => {
clone.style.left = `${subscriptionRect.left}px`;
clone.style.top = `${subscriptionRect.top}px`;
clone.style.width = '0';
clone.style.height = '0';
clone.style.opacity = '0';
}, 100);
setTimeout(() => {
document.body.removeChild(clone);
}, 600);
}
async function consultationFunction() {
@ -362,10 +763,16 @@
function deleteSubscribedNews(index) {
const subscribedNews = JSON.parse(localStorage.getItem('subscribedNews') || '[]');
subscribedNews.splice(index, 1);
localStorage.setItem('subscribedNews', JSON.stringify(subscribedNews));
showSubscribedNews();
updateSubscriptionCount();
const subscriptionList = document.getElementById('subscriptionList');
const newsItem = subscriptionList.querySelectorAll('.subscribed-news-item')[index];
newsItem.style.animation = 'shatter 0.5s forwards';
setTimeout(() => {
subscribedNews.splice(index, 1);
localStorage.setItem('subscribedNews', JSON.stringify(subscribedNews));
showSubscribedNews();
updateSubscriptionCount();
}, 500);
}
function updateSubscriptionCount() {
@ -407,6 +814,85 @@
}
});
});
function deleteSubscribedNews(index) {
const subscribedNews = JSON.parse(localStorage.getItem('subscribedNews') || '[]');
const subscriptionList = document.getElementById('subscriptionList');
const newsItem = subscriptionList.querySelectorAll('.subscribed-news-item')[index];
const rect = newsItem.getBoundingClientRect();
// 创建爆炸中心光效
const explosionCenter = document.createElement('div');
explosionCenter.className = 'explosion-center';
explosionCenter.style.left = `${rect.left + rect.width / 2}px`;
explosionCenter.style.top = `${rect.top + rect.height / 2}px`;
document.body.appendChild(explosionCenter);
// 创建大量粒子
const particleCount = 30; // 增加粒子数量
const colors = [
'#ff4444', '#ff6b6b', '#ff8888', '#ffaaaa',
'#ff0000', '#ff3333', '#ff6666', '#ff9999'
];
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
// 随机颜色
particle.style.background = colors[Math.floor(Math.random() * colors.length)];
// 设置初始位置(爆炸中心)
particle.style.left = `${rect.left + rect.width / 2}px`;
particle.style.top = `${rect.top + rect.height / 2}px`;
// 随机运动参数
const angle = (Math.PI * 2 * i) / particleCount; // 均匀分布的角度
const velocity = 300 + Math.random() * 400; // 增加速度范围
const tx = Math.cos(angle) * velocity;
const ty = Math.sin(angle) * velocity;
const rotate = Math.random() * 1080; // 增加旋转角度
// 设置动画属性
particle.style.setProperty('--tx', `${tx}px`);
particle.style.setProperty('--ty', `${ty}px`);
particle.style.setProperty('--rotate', `${rotate}deg`);
// 添加动画
particle.style.animation = `particle-explosion 0.8s cubic-bezier(.17,.67,.83,.67) forwards`;
document.body.appendChild(particle);
// 动画结束后清理
setTimeout(() => {
document.body.removeChild(particle);
}, 800);
}
// 添加震动效果
newsItem.style.animation = 'shake 0.2s ease-in';
// 清理和更新数据
setTimeout(() => {
document.body.removeChild(explosionCenter);
subscribedNews.splice(index, 1);
localStorage.setItem('subscribedNews', JSON.stringify(subscribedNews));
showSubscribedNews();
updateSubscriptionCount();
}, 300);
}
// 添加震动动画
const shakeKeyframes = `
@keyframes shake {
0%, 100% { transform: translate(0, 0) rotate(0deg); }
25% { transform: translate(-10px, 0) rotate(-5deg); }
75% { transform: translate(10px, 0) rotate(5deg); }
}`;
const styleSheet = document.createElement('style');
styleSheet.textContent = shakeKeyframes;
document.head.appendChild(styleSheet);
</script>
</head>
<body>

@ -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;
}
</style>
</head>
<body>
<!-- 其余HTML内容保持不变 -->
<div id="app">
<header>
<h1>个性化法律学习计划</h1>
@ -43,6 +281,41 @@
<div id="results-container"></div>
<div class="file-export-section">
<h3>历史记录导出</h3>
<div class="file-selector">
<label>
<input type="checkbox" v-model="selectedRecords" value="terms">
<span>法律术语搜索记录</span>
</label>
<label>
<input type="checkbox" v-model="selectedRecords" value="consultation">
<span>法律咨询记录</span>
</label>
<label>
<input type="checkbox" v-model="selectedRecords" value="cases">
<span>案例匹配记录</span>
</label>
<label>
<input type="checkbox" v-model="selectedRecords" value="news">
<span>法律新闻订阅记录</span>
</label>
</div>
<button class="export-btn" @click="exportRecords">
<i class="fas fa-download"></i> 导出选中记录
</button>
</div>
<div class="popup-menu" v-show="showPopup" :style="popupStyle">
<div class="popup-item"
v-for="item in popupItems"
:key="item.id"
:class="{ selected: isItemSelected(item) }"
@click="toggleSelection(item)">
{{ item.name }}
</div>
</div>
<footer>
<p>&copy; 2024 智能法律服务系统</p>
</footer>
@ -50,40 +323,141 @@
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const searchEngines = [
'https://www.baidu.com/s?wd=',
'https://www.sogou.com/web?query=',
'https://cn.bing.com/search?q='
];
function searchLegalResources() {
const userInput = document.getElementById('consultation-input').value;
if (!userInput) {
alert('请输入搜索关键词');
return;
}
const searchQuery = encodeURIComponent(userInput + " 法律学习");
const searchUrl = searchEngines[Math.floor(Math.random() * searchEngines.length)] + searchQuery;
window.open(searchUrl, '_blank');
}
document.addEventListener('DOMContentLoaded', function() {
const inputElement = document.getElementById('consultation-input');
inputElement.addEventListener('keyup', function(event) {
if (event.key === 'Enter') {
searchLegalResources();
// JavaScript代码保持不变
const searchEngines = [
'https://www.baidu.com/s?wd=',
'https://www.sogou.com/web?query=',
'https://cn.bing.com/search?q='
];
function searchLegalResources() {
const userInput = document.getElementById('consultation-input').value;
if (!userInput) {
alert('请输入搜索关键词');
return;
}
});
});
new Vue({
el: '#app',
methods: {
searchLegalResources
const searchQuery = encodeURIComponent(userInput + " 法律学习");
const searchUrl = searchEngines[Math.floor(Math.random() * searchEngines.length)] + searchQuery;
window.open(searchUrl, '_blank');
}
});
document.addEventListener('DOMContentLoaded', function() {
const inputElement = document.getElementById('consultation-input');
inputElement.addEventListener('keyup', function(event) {
if (event.key === 'Enter') {
searchLegalResources();
}
});
});
new Vue({
el: '#app',
data: {
selectedRecords: [],
showPopup: false,
popupStyle: {
top: '0px',
left: '0px'
},
popupItems: [],
selectedItems: new Set()
},
methods: {
searchLegalResources,
showContextMenu(event) {
event.preventDefault();
this.showPopup = true;
this.popupStyle = {
top: `${event.clientY}px`,
left: `${event.clientX}px`
};
this.loadPopupItems(event.target);
},
loadPopupItems(target) {
const type = target.dataset.type;
switch(type) {
case 'news':
this.popupItems = JSON.parse(localStorage.getItem('newsSubscription') || '[]')
.map(item => ({
id: item.timestamp,
name: item.news.title,
type: 'news'
}));
break;
case 'terms':
this.popupItems = JSON.parse(localStorage.getItem('termsHistory') || '[]')
.map(item => ({
id: item.timestamp,
name: item.term,
type: 'terms'
}));
break;
}
},
isItemSelected(item) {
return this.selectedItems.has(item.id);
},
toggleSelection(item) {
if (this.selectedItems.has(item.id)) {
this.selectedItems.delete(item.id);
} else {
this.selectedItems.add(item.id);
}
},
exportRecords() {
if (this.selectedRecords.length === 0 && this.selectedItems.size === 0) {
alert('请至少选择一项记录进行导出');
return;
}
let exportData = {};
this.selectedRecords.forEach(recordType => {
switch(recordType) {
case 'terms':
exportData.terms = JSON.parse(localStorage.getItem('termsHistory') || '[]');
break;
case 'consultation':
exportData.consultation = JSON.parse(localStorage.getItem('consultationHistory') || '[]');
break;
case 'cases':
exportData.cases = JSON.parse(localStorage.getItem('casesHistory') || '[]');
break;
case 'news':
exportData.news = JSON.parse(localStorage.getItem('newsSubscription') || '[]');
break;
}
});
if (this.selectedItems.size > 0) {
exportData.selectedItems = Array.from(this.selectedItems);
}
const dataStr = JSON.stringify(exportData, 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);
}
},
mounted() {
document.addEventListener('contextmenu', this.showContextMenu);
document.addEventListener('click', () => {
this.showPopup = false;
});
},
beforeDestroy() {
document.removeEventListener('contextmenu', this.showContextMenu);
}
});
</script>
</body>
</html>
Loading…
Cancel
Save