合并代码 #829

Merged
durian merged 59 commits from gitlink_ssr_head into pre_gitlink_ssr 2026-06-12 14:03:42 +08:00
85 changed files with 5572 additions and 138 deletions

View File

@ -8,6 +8,10 @@
font-family: "pangmen";
src: url("../fonts/PangMenZhengDaoBiaoTiTiMianFeiBan-2.ttf");
}
@font-face {
font-family: "sanjikai";
src: url("../fonts/SanJiXingKaiJianTi-Cu-2.ttf");
}
@font-face {
font-family: "alibaba";
src: url("../fonts/ALIBABA-PUHUITI-MEDIUM.TTF");
@ -16,6 +20,10 @@
font-family: "alibabaReg";
src: url("../fonts/ALIBABA-PUHUITI-REGULAR.TTF");
}
@font-face {
font-family: "alibabaBold";
src: url("../fonts/ALIBABA-PUHUITI-BOLD.TTF");
}
@font-face {
font-family: "ziyouwenyihei";
src: url("../fonts/ziyouwenyihei.ttf");

View File

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@ -0,0 +1,109 @@
@font-face {
font-family: "iconfont-color"; /* Project id 5169666 */
/* Color fonts */
src:
url('iconfont.woff2?t=1780903107408') format('woff2'),
url('iconfont.woff?t=1780903107408') format('woff'),
url('iconfont.ttf?t=1780903107408') format('truetype');
}
.iconfont-color {
font-family: "iconfont-color" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-colorzuojiantou:before {
content: "\e6d4";
}
.icon-coloryoujiantou:before {
content: "\e6d5";
}
.icon-colorqita:before {
content: "\e7b3";
}
.icon-coloryidongkaifa:before {
content: "\e7b4";
}
.icon-colordaimazhijian:before {
content: "\e7b5";
}
.icon-coloryunxiaogongju:before {
content: "\e7b6";
}
.icon-coloryouxiyule:before {
content: "\e7b7";
}
.icon-colorskill:before {
content: "\e7b0";
}
.icon-colorshujuji:before {
content: "\e7b1";
}
.icon-colordaimaku1:before {
content: "\e7b2";
}
.icon-colormoxingku:before {
content: "\e7af";
}
.icon-coloryinpin:before {
content: "\e7ad";
}
.icon-colorremenmoxing-1:before {
content: "\e7a3";
}
.icon-colorkexueyanjiuhejishufuwuye:before {
content: "\e7ae";
}
.icon-colora-zu18210:before {
content: "\e7a6";
}
.icon-colora-zu18240:before {
content: "\e7a5";
}
.icon-colora-zuixin1:before {
content: "\e7a7";
}
.icon-colorziranyuyanchuli:before {
content: "\e7a8";
}
.icon-colorshichangtuiguang-01:before {
content: "\e7a4";
}
.icon-coloryuyin:before {
content: "\e7a9";
}
.icon-colortuxiang:before {
content: "\e7aa";
}
.icon-colora-zu18213:before {
content: "\e7ab";
}
.icon-colorshipinbofang:before {
content: "\e7ac";
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,170 @@
{
"id": "5169666",
"name": "newForge-color",
"font_family": "iconfont-color",
"css_prefix_text": "icon-color",
"description": "gitlink/红山开源 带颜色的icon",
"glyphs": [
{
"icon_id": "47799227",
"name": "左箭头",
"font_class": "zuojiantou",
"unicode": "e6d4",
"unicode_decimal": 59092
},
{
"icon_id": "47799226",
"name": "右箭头",
"font_class": "youjiantou",
"unicode": "e6d5",
"unicode_decimal": 59093
},
{
"icon_id": "47487873",
"name": "其他",
"font_class": "qita",
"unicode": "e7b3",
"unicode_decimal": 59315
},
{
"icon_id": "47487872",
"name": "移动开发",
"font_class": "yidongkaifa",
"unicode": "e7b4",
"unicode_decimal": 59316
},
{
"icon_id": "47487870",
"name": "代码质检",
"font_class": "daimazhijian",
"unicode": "e7b5",
"unicode_decimal": 59317
},
{
"icon_id": "47487871",
"name": "云效工具",
"font_class": "yunxiaogongju",
"unicode": "e7b6",
"unicode_decimal": 59318
},
{
"icon_id": "47487869",
"name": "游戏娱乐",
"font_class": "youxiyule",
"unicode": "e7b7",
"unicode_decimal": 59319
},
{
"icon_id": "47487614",
"name": "skill",
"font_class": "skill",
"unicode": "e7b0",
"unicode_decimal": 59312
},
{
"icon_id": "47487615",
"name": "数据集",
"font_class": "shujuji",
"unicode": "e7b1",
"unicode_decimal": 59313
},
{
"icon_id": "47487613",
"name": "代码库",
"font_class": "daimaku1",
"unicode": "e7b2",
"unicode_decimal": 59314
},
{
"icon_id": "47487578",
"name": "模型库",
"font_class": "moxingku",
"unicode": "e7af",
"unicode_decimal": 59311
},
{
"icon_id": "47470053",
"name": "音频",
"font_class": "yinpin",
"unicode": "e7ad",
"unicode_decimal": 59309
},
{
"icon_id": "47470038",
"name": "热门模型-1",
"font_class": "remenmoxing-1",
"unicode": "e7a3",
"unicode_decimal": 59299
},
{
"icon_id": "47470036",
"name": "科学研究和技术服务业",
"font_class": "kexueyanjiuhejishufuwuye",
"unicode": "e7ae",
"unicode_decimal": 59310
},
{
"icon_id": "47470068",
"name": "组 18210",
"font_class": "a-zu18210",
"unicode": "e7a6",
"unicode_decimal": 59302
},
{
"icon_id": "47470067",
"name": "组 18240",
"font_class": "a-zu18240",
"unicode": "e7a5",
"unicode_decimal": 59301
},
{
"icon_id": "47470066",
"name": "最新 (1)",
"font_class": "a-zuixin1",
"unicode": "e7a7",
"unicode_decimal": 59303
},
{
"icon_id": "47470060",
"name": "自然语言处理",
"font_class": "ziranyuyanchuli",
"unicode": "e7a8",
"unicode_decimal": 59304
},
{
"icon_id": "47470052",
"name": "市场推广-01",
"font_class": "shichangtuiguang-01",
"unicode": "e7a4",
"unicode_decimal": 59300
},
{
"icon_id": "47470056",
"name": "语音",
"font_class": "yuyin",
"unicode": "e7a9",
"unicode_decimal": 59305
},
{
"icon_id": "47470055",
"name": "图像",
"font_class": "tuxiang",
"unicode": "e7aa",
"unicode_decimal": 59306
},
{
"icon_id": "47470057",
"name": "组 18213",
"font_class": "a-zu18213",
"unicode": "e7ab",
"unicode_decimal": 59307
},
{
"icon_id": "47470047",
"name": "视频播放",
"font_class": "shipinbofang",
"unicode": "e7ac",
"unicode_decimal": 59308
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
src: url('iconfont.woff2?t=1768876676007') format('woff2'),
url('iconfont.woff?t=1768876676007') format('woff'),
url('iconfont.ttf?t=1768876676007') format('truetype');
src: url('iconfont.woff2?t=1780902820324') format('woff2'),
url('iconfont.woff?t=1780902820324') format('woff'),
url('iconfont.ttf?t=1780902820324') format('truetype');
}
.iconfont {
@ -13,6 +13,258 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-zuojiantou3:before {
content: "\ea05";
}
.icon-youjiantou2:before {
content: "\ea06";
}
.icon-fanhuagongju:before {
content: "\ea02";
}
.icon-jingxuanxiangmu1:before {
content: "\ea03";
}
.icon-gengduo2:before {
content: "\ea04";
}
.icon-shengwuyiyao:before {
content: "\e9f5";
}
.icon-youjiantou1:before {
content: "\e9fa";
}
.icon-zuojiantou2:before {
content: "\e9fd";
}
.icon-daqihaiyanghuanjing:before {
content: "\e9fe";
}
.icon-tianwendiliwuli:before {
content: "\e9ff";
}
.icon-xinnengyuanxincailiao:before {
content: "\ea00";
}
.icon-gongyeshejizhizao:before {
content: "\ea01";
}
.icon-tiezi:before {
content: "\e9f4";
}
.icon-xiala5:before {
content: "\e9df";
}
.icon-yulan:before {
content: "\e9f1";
}
.icon-arrright:before {
content: "\e9fc";
}
.icon-yunxiaogongju:before {
content: "\e9f6";
}
.icon-daimazhijian:before {
content: "\e9f7";
}
.icon-yidongkaifa:before {
content: "\e9f8";
}
.icon-qita:before {
content: "\e9f9";
}
.icon-meitichuli:before {
content: "\e9fb";
}
.icon-skill:before {
content: "\e9f3";
}
.icon-daimaku1:before {
content: "\e9f2";
}
.icon-dianzan5:before {
content: "\e9ee";
}
.icon-duomotaimoxing:before {
content: "\e9ef";
}
.icon-a-kexueyanjiuhejishufuwuye-1:before {
content: "\e9f0";
}
.icon-yinpin-1:before {
content: "\e9e2";
}
.icon-shujuji-4:before {
content: "\e9e4";
}
.icon-shujuji:before {
content: "\e9e5";
}
.icon-shujuyuanmoxing:before {
content: "\e9e6";
}
.icon-shujuji-3:before {
content: "\e9e7";
}
.icon-a-shujuji5:before {
content: "\e9e8";
}
.icon-a-shujuji-6:before {
content: "\e9e9";
}
.icon-shipinbofang-1:before {
content: "\e9ea";
}
.icon-moxingku:before {
content: "\e9eb";
}
.icon-a-shijianzhongbiao:before {
content: "\e9ec";
}
.icon-remenmoxing-2:before {
content: "\e9ed";
}
.icon-a-Dshujukukaifagongju:before {
content: "\e9cd";
}
.icon-ziranyuyanchuli-2:before {
content: "\e9db";
}
.icon-a-zu18214:before {
content: "\e9dc";
}
.icon-zizhushujuji:before {
content: "\e9dd";
}
.icon-yuyin-1:before {
content: "\e9de";
}
.icon-a-tuxiang-1:before {
content: "\e9e0";
}
.icon-xiazai3:before {
content: "\e9e1";
}
.icon-shijian1:before {
content: "\e9cb";
}
.icon-liulanliang:before {
content: "\e9cc";
}
.icon-guanbi2:before {
content: "\e9ca";
}
.icon-zhanshishangxian1:before {
content: "\e9d3";
}
.icon-tianxiexinxi:before {
content: "\e9d8";
}
.icon-tijiaoshenqing1:before {
content: "\e9d9";
}
.icon-guanliyuanshenhe1:before {
content: "\e9da";
}
.icon-sixin2:before {
content: "\e9e3";
}
.icon-dianzan4:before {
content: "\e9d6";
}
.icon-liulanshu:before {
content: "\e9d7";
}
.icon-tiezishu:before {
content: "\e9ce";
}
.icon-yanjiulingyu:before {
content: "\e9cf";
}
.icon-a-xiugai3:before {
content: "\e9d0";
}
.icon-yitijiaoderuzhuxinxi:before {
content: "\e9d1";
}
.icon-sixin:before {
content: "\e9d2";
}
.icon-gerenjianjie:before {
content: "\e9d4";
}
.icon-guanzhu1:before {
content: "\e9d5";
}
.icon-woyefatie:before {
content: "\e9c9";
}
.icon-yingyongmoban:before {
content: "\e9c8";
}
.icon-zhuangtai:before {
content: "\e9c5";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,447 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "47798947",
"name": "左箭头",
"font_class": "zuojiantou3",
"unicode": "ea05",
"unicode_decimal": 59909
},
{
"icon_id": "47798946",
"name": "右箭头",
"font_class": "youjiantou2",
"unicode": "ea06",
"unicode_decimal": 59910
},
{
"icon_id": "47778051",
"name": "泛化工具",
"font_class": "fanhuagongju",
"unicode": "ea02",
"unicode_decimal": 59906
},
{
"icon_id": "47778050",
"name": "精选项目",
"font_class": "jingxuanxiangmu1",
"unicode": "ea03",
"unicode_decimal": 59907
},
{
"icon_id": "47778049",
"name": "更多",
"font_class": "gengduo2",
"unicode": "ea04",
"unicode_decimal": 59908
},
{
"icon_id": "47778058",
"name": "生物医药",
"font_class": "shengwuyiyao",
"unicode": "e9f5",
"unicode_decimal": 59893
},
{
"icon_id": "47778057",
"name": "右箭头",
"font_class": "youjiantou1",
"unicode": "e9fa",
"unicode_decimal": 59898
},
{
"icon_id": "47778056",
"name": "左箭头",
"font_class": "zuojiantou2",
"unicode": "e9fd",
"unicode_decimal": 59901
},
{
"icon_id": "47778052",
"name": "大气海洋环境",
"font_class": "daqihaiyanghuanjing",
"unicode": "e9fe",
"unicode_decimal": 59902
},
{
"icon_id": "47778055",
"name": "天文地理物理",
"font_class": "tianwendiliwuli",
"unicode": "e9ff",
"unicode_decimal": 59903
},
{
"icon_id": "47778054",
"name": "新能源新材料",
"font_class": "xinnengyuanxincailiao",
"unicode": "ea00",
"unicode_decimal": 59904
},
{
"icon_id": "47778053",
"name": "工业设计制造",
"font_class": "gongyeshejizhizao",
"unicode": "ea01",
"unicode_decimal": 59905
},
{
"icon_id": "47756092",
"name": "帖子",
"font_class": "tiezi",
"unicode": "e9f4",
"unicode_decimal": 59892
},
{
"icon_id": "47540662",
"name": "下拉",
"font_class": "xiala5",
"unicode": "e9df",
"unicode_decimal": 59871
},
{
"icon_id": "47540661",
"name": "预览",
"font_class": "yulan",
"unicode": "e9f1",
"unicode_decimal": 59889
},
{
"icon_id": "40883122",
"name": "长箭头-copy",
"font_class": "arrright",
"unicode": "e9fc",
"unicode_decimal": 59900
},
{
"icon_id": "47487774",
"name": "云效工具",
"font_class": "yunxiaogongju",
"unicode": "e9f6",
"unicode_decimal": 59894
},
{
"icon_id": "47487775",
"name": "代码质检",
"font_class": "daimazhijian",
"unicode": "e9f7",
"unicode_decimal": 59895
},
{
"icon_id": "47487773",
"name": "移动开发",
"font_class": "yidongkaifa",
"unicode": "e9f8",
"unicode_decimal": 59896
},
{
"icon_id": "47487772",
"name": "其他",
"font_class": "qita",
"unicode": "e9f9",
"unicode_decimal": 59897
},
{
"icon_id": "47487770",
"name": "媒体处理",
"font_class": "meitichuli",
"unicode": "e9fb",
"unicode_decimal": 59899
},
{
"icon_id": "47487669",
"name": "skill",
"font_class": "skill",
"unicode": "e9f3",
"unicode_decimal": 59891
},
{
"icon_id": "47487670",
"name": "代码库",
"font_class": "daimaku1",
"unicode": "e9f2",
"unicode_decimal": 59890
},
{
"icon_id": "47470076",
"name": "点赞",
"font_class": "dianzan5",
"unicode": "e9ee",
"unicode_decimal": 59886
},
{
"icon_id": "47470075",
"name": "多模态模型",
"font_class": "duomotaimoxing",
"unicode": "e9ef",
"unicode_decimal": 59887
},
{
"icon_id": "47470074",
"name": "科学研究和技术服务业 -1",
"font_class": "a-kexueyanjiuhejishufuwuye-1",
"unicode": "e9f0",
"unicode_decimal": 59888
},
{
"icon_id": "47470091",
"name": "音频-1",
"font_class": "yinpin-1",
"unicode": "e9e2",
"unicode_decimal": 59874
},
{
"icon_id": "47470090",
"name": "数据集-4",
"font_class": "shujuji-4",
"unicode": "e9e4",
"unicode_decimal": 59876
},
{
"icon_id": "47470088",
"name": "数据集",
"font_class": "shujuji",
"unicode": "e9e5",
"unicode_decimal": 59877
},
{
"icon_id": "47470089",
"name": "数据源模型",
"font_class": "shujuyuanmoxing",
"unicode": "e9e6",
"unicode_decimal": 59878
},
{
"icon_id": "47470087",
"name": "数据集-3",
"font_class": "shujuji-3",
"unicode": "e9e7",
"unicode_decimal": 59879
},
{
"icon_id": "47470086",
"name": "数据集 (5)",
"font_class": "a-shujuji5",
"unicode": "e9e8",
"unicode_decimal": 59880
},
{
"icon_id": "47470083",
"name": "数据集 -6",
"font_class": "a-shujuji-6",
"unicode": "e9e9",
"unicode_decimal": 59881
},
{
"icon_id": "47470084",
"name": "视频播放-1",
"font_class": "shipinbofang-1",
"unicode": "e9ea",
"unicode_decimal": 59882
},
{
"icon_id": "47470081",
"name": "模型库",
"font_class": "moxingku",
"unicode": "e9eb",
"unicode_decimal": 59883
},
{
"icon_id": "47470080",
"name": "时间 钟表",
"font_class": "a-shijianzhongbiao",
"unicode": "e9ec",
"unicode_decimal": 59884
},
{
"icon_id": "47470079",
"name": "热门模型-2",
"font_class": "remenmoxing-2",
"unicode": "e9ed",
"unicode_decimal": 59885
},
{
"icon_id": "47470107",
"name": "D+数据库开发工具",
"font_class": "a-Dshujukukaifagongju",
"unicode": "e9cd",
"unicode_decimal": 59853
},
{
"icon_id": "47470101",
"name": "自然语言处理-2",
"font_class": "ziranyuyanchuli-2",
"unicode": "e9db",
"unicode_decimal": 59867
},
{
"icon_id": "47470102",
"name": "组 18214",
"font_class": "a-zu18214",
"unicode": "e9dc",
"unicode_decimal": 59868
},
{
"icon_id": "47470098",
"name": "自助数据集",
"font_class": "zizhushujuji",
"unicode": "e9dd",
"unicode_decimal": 59869
},
{
"icon_id": "47470095",
"name": "语音-1",
"font_class": "yuyin-1",
"unicode": "e9de",
"unicode_decimal": 59870
},
{
"icon_id": "47470094",
"name": "图像 -1",
"font_class": "a-tuxiang-1",
"unicode": "e9e0",
"unicode_decimal": 59872
},
{
"icon_id": "47470092",
"name": "下载",
"font_class": "xiazai3",
"unicode": "e9e1",
"unicode_decimal": 59873
},
{
"icon_id": "47464883",
"name": "时间",
"font_class": "shijian1",
"unicode": "e9cb",
"unicode_decimal": 59851
},
{
"icon_id": "47464882",
"name": "浏览量",
"font_class": "liulanliang",
"unicode": "e9cc",
"unicode_decimal": 59852
},
{
"icon_id": "47337195",
"name": "关闭",
"font_class": "guanbi2",
"unicode": "e9ca",
"unicode_decimal": 59850
},
{
"icon_id": "47202525",
"name": "展示上线",
"font_class": "zhanshishangxian1",
"unicode": "e9d3",
"unicode_decimal": 59859
},
{
"icon_id": "47202524",
"name": "填写信息",
"font_class": "tianxiexinxi",
"unicode": "e9d8",
"unicode_decimal": 59864
},
{
"icon_id": "47202523",
"name": "提交申请",
"font_class": "tijiaoshenqing1",
"unicode": "e9d9",
"unicode_decimal": 59865
},
{
"icon_id": "47202522",
"name": "管理员审核",
"font_class": "guanliyuanshenhe1",
"unicode": "e9da",
"unicode_decimal": 59866
},
{
"icon_id": "47195847",
"name": "私信",
"font_class": "sixin2",
"unicode": "e9e3",
"unicode_decimal": 59875
},
{
"icon_id": "47195594",
"name": "点赞",
"font_class": "dianzan4",
"unicode": "e9d6",
"unicode_decimal": 59862
},
{
"icon_id": "47195591",
"name": "浏览数",
"font_class": "liulanshu",
"unicode": "e9d7",
"unicode_decimal": 59863
},
{
"icon_id": "47195601",
"name": "帖子数",
"font_class": "tiezishu",
"unicode": "e9ce",
"unicode_decimal": 59854
},
{
"icon_id": "47195600",
"name": "研究领域",
"font_class": "yanjiulingyu",
"unicode": "e9cf",
"unicode_decimal": 59855
},
{
"icon_id": "47195597",
"name": "修改 (3)",
"font_class": "a-xiugai3",
"unicode": "e9d0",
"unicode_decimal": 59856
},
{
"icon_id": "47195598",
"name": "已提交的入驻信息",
"font_class": "yitijiaoderuzhuxinxi",
"unicode": "e9d1",
"unicode_decimal": 59857
},
{
"icon_id": "47195599",
"name": "私信",
"font_class": "sixin",
"unicode": "e9d2",
"unicode_decimal": 59858
},
{
"icon_id": "47195593",
"name": "个人简介",
"font_class": "gerenjianjie",
"unicode": "e9d4",
"unicode_decimal": 59860
},
{
"icon_id": "47195595",
"name": "关注",
"font_class": "guanzhu1",
"unicode": "e9d5",
"unicode_decimal": 59861
},
{
"icon_id": "47139445",
"name": "我也发帖",
"font_class": "woyefatie",
"unicode": "e9c9",
"unicode_decimal": 59849
},
{
"icon_id": "46808654",
"name": "应用模板",
"font_class": "yingyongmoban",
"unicode": "e9c8",
"unicode_decimal": 59848
},
{
"icon_id": "46593376",
"name": "状态",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -31,6 +31,7 @@
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/alex/alex.all.global.min.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont-color/iconfont.css">
<!-- <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/edu-purge.css"> -->
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/editormd.min.css">
<!-- <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/merge.css"> -->

View File

@ -0,0 +1,175 @@
import React, { useEffect, useState } from 'react';
import { Modal, Button, Form, Input } from 'antd';
import cookie from 'react-cookies';
import { getZoneUrl } from 'educoder';
import IconImg from '../img/user/icon1.png';
import TemplateImg from '../img/user/template.png';
import { applyAward } from '../api';
import { httpUrl } from '../fetch';
import '../indexUser.scss';
function UserAward({ visible , onCancel , onSure , member , id, form }) {
const [ loading , setLoading ] = useState(false);
const [ score , setScore ] = useState(0);
const [ scoreLeft , setScoreLeft ] = useState(0);
const { getFieldDecorator, validateFields, getFieldsValue } = form;
useEffect(()=>{
if(visible && member && member.zonePointsAccount && member.zonePointsAccount.availablePoints) {
setScore(member.zonePointsAccount.availablePoints);
setScoreLeft(member.zonePointsAccount.availablePoints - 200);
}
},[visible, member])
function onOk() {
validateFields(async (err, values) => {
if (!err) {
try{
setLoading(true);
let imgInfo = await createImg(values.realName);
let certificateUrl = '';
if (imgInfo && imgInfo.code == 200 && imgInfo.url) {
certificateUrl = imgInfo.url || '';
}
const res = await applyAward({zoneId: id, sourceData: certificateUrl});
setLoading(false);
if (res && res.data && res.data.code === 200) {
onSure(res.data.msg);
}
}finally{
setLoading(false);
}
}
});
}
async function waitFontLoaded() {
//
if (document.fonts) {
await document.fonts.ready;
if(!document.fonts.check('64px sanjikai')) {
try {
const font = new FontFace('sanjikai', `url(${process.env.PUBLIC_URL}/fonts/SanJiXingKaiJianTi-Cu-2.ttf)`);
await font.load();
document.fonts.add(font);
} catch (e) {
console.warn('sanjikai 字体加载失败:', e);
}
}
if(!document.fonts.check('18px alibabaReg')) {
try {
const font = new FontFace('alibabaReg', `url(${process.env.PUBLIC_URL}/fonts/ALIBABA-PUHUITI-REGULAR.TTF)`);
await font.load();
document.fonts.add(font);
} catch (e) {
console.warn('alibabaReg 字体加载失败:', e);
}
}
}
}
async function createImg(realName) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.crossOrigin = 'anonymous';
img.src = TemplateImg;
await new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
});
//
await waitFontLoaded();
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const memberName = realName || member?.name || member?.nickname || '学员';
const awardDate = new Date().toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' });
//
ctx.font = '64px sanjikai';
ctx.fillStyle = '#04060c';
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillText(memberName, canvas.width / 2, 705);
ctx.font = '18px alibabaReg';
ctx.fillStyle = '#04060c';
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText(awardDate, 240, 1008);
const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
const formData = new FormData();
formData.append('file', blob, `${realName}_电子荣誉证书.png`);
formData.append('type', 'resource');
const uploadRes = await fetch(`${getZoneUrl(`/api/file/common/upload`)}`, {
method: 'POST',
body: formData,
credentials: 'include',
});
const uploadData = await uploadRes.json();
return uploadData;
}
return(
<Modal
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={onCancel}></i>}
className="user_modal"
visible={visible}
title={<div className="title_box">
<img alt="头像" src={IconImg} style={{width: '48px', height: '48px'}}></img>
<div className="txt">
<h4>
兑换专属电子荣誉证书
</h4>
<p>超算专区<span> · </span>积分兑换</p>
</div>
</div>}
closable={true}
width={672}
footer={
<div>
<Button onClick={onCancel}>取消</Button>
<Button className="btn_ok" style={{marginLeft:"20px"}} onClick={onOk} loading={loading}>确定</Button>
</div>
}
okText="确定"
cancelText="取消"
>
<div className="info">
<p className="award">您将消耗<label> 200 积分 </label>兑换专属电子荣誉证书当前可用积分 {score.toLocaleString()} 兑换后剩余 {scoreLeft.toLocaleString()} 积分扣除后将自动生成证书无法退回请确认操作请确认是否兑换专属电子荣誉证书</p>
<Form form={form}>
<Form.Item label="真实姓名">
{getFieldDecorator('realName', {
rules: [
{
required: true,
message: '请输入真实姓名'
}
],
})(
<Input placeholder="请输入真实姓名" maxLength={20} />,
)}
</Form.Item>
</Form>
</div>
</Modal>
)
}
export default Form.create()(UserAward);

View File

@ -0,0 +1,136 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Button, Upload, message, Icon } from 'antd';
import { getImageUrlAbsolute, getZoneUrl } from 'educoder';
import cookie from 'react-cookies';
const TokenKey = 'autologin_trustie';
const { TextArea } = Input;
import IconImg from '../img/user/icon.png';
import '../indexUser.scss';
function UserEdit({ visible, onCancel, form, onSure, type, zoneName, choosed, history, showCompeleteDialog, member, maxSize = 2 }) {
const [imageUrl, setImageUrl] = useState(undefined)
const [loading, setLoading] = useState(false);
const { getFieldDecorator, validateFields } = form;
useEffect(() => {
if (visible && member) {
form.setFieldsValue({
name: member.name || '',
introduction: member.introduction || ''
});
setImageUrl(member.imageUrl || '');
}
}, [visible, member]);
function onOk() {
validateFields((err, values) => {
if (!err) {
let temp = Object.assign({}, values, { imageUrl: imageUrl })
if (onSure) {
onSure(temp);
}
}
});
}
function closeHandler() {
// form.resetFields();
onCancel();
}
//
function beforeUpload(file){
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('上传的图片只能是JPG或者PNG格式!');
}
const isLt2M = file.size / 1024 / 1024 < maxSize;
if (!isLt2M) {
message.error(`上传的图片不能超过${maxSize}MB!`);
}
isJpgOrPng && isLt2M && setLoading(true);
return isJpgOrPng && isLt2M;
}
//
function handleChange(info){
if(info && info.file && info.file.status === "done"){
setLoading(false);
setImageUrl(info.file.response.url);
}
}
return(
<Modal
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={closeHandler}></i>}
className="user_modal"
visible={visible}
title={<div className="title_box">
<img alt="头像" src={IconImg} style={{width: '48px', height: '48px'}}></img>
<div className="txt">
<h4>
个人资料管理
</h4>
<p>{zoneName}<span> · </span>会员资料设置</p>
</div>
</div>}
closable={true}
width={672}
footer={
<div>
<Button onClick={closeHandler}>取消</Button>
<Button className="btn_ok" style={{marginLeft:"20px"}} onClick={onOk}>确定</Button>
</div>
}
okText="确定"
cancelText="取消"
>
<div className="info">
<div className="avatar">
<img src={imageUrl}></img>
<div style={{flex: 1}}>
<div className="box">
<Upload action={getZoneUrl(`/api/file/common/upload`)}
// getZoneUrl(`/api/cms/common/upload`)
beforeUpload={beforeUpload}
onChange={handleChange}
showUploadList={false}
withCredentials={ true }
headers={{ Authorization: cookie.load(TokenKey) }}
accept=".png,.jpg,.jpeg">
<span className="uploadtxt">
{/* <i className="iconfont icon-shangchuanicon font-14"/> */}
<Icon type={loading ? 'loading' : 'upload'} />
上传本地图片</span>
{/* <Button icon={<i className="iconfont icon-shangchuanicon font-14"></i>}>上传本地图片</Button> */}
</Upload>
</div>
<p>支持 JPGPNG 格式 · 大小不超过 2MB建议尺寸 200×200px 以上效果更佳</p>
</div>
</div>
<Form form={form}>
<Form.Item label="会员昵称" name="name" rules={[{ required: true, message: '请输入会员昵称' }]}>
{getFieldDecorator('name', {
rules: [
{
required:true,
message:"请输入您的昵称1-20个字符"
}
],
})(
<Input placeholder="请输入会员昵称" maxLength={ 20 } width="220px" showcount="true" />,
)}
</Form.Item>
<Form.Item label="会员简介" name="introduction">
{getFieldDecorator('introduction')(
<TextArea maxLength={200} placeholder="介绍一下您的研究领域或个人简介,让更多伙伴了解您…" autoSize={{ minRows: 3, maxRows: 3 }} showcount="true" />,
)}
</Form.Item>
</Form>
</div>
</Modal>
)
}
export default Form.create()(UserEdit);

View File

@ -0,0 +1,133 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Button, Row, Col } from 'antd';
import { doApplyActivity } from '../api';
const { TextArea } = Input;
import IconImg from '../img/user/icon1.png';
import '../indexUser.scss';
function ApplyActivity({ visible, onCancel, onSure, form, member, zoneName, }) {
const [loading, setLoading] = useState(false);
const { getFieldDecorator, validateFields } = form;
useEffect(() => {
if (visible) {
}
}, [visible]);
function onOk() {
validateFields((err, values) => {
if (!err) {
setLoading(true);
const data = Object.assign({}, values, { zoneId: member.zoneId });
doApplyActivity(data).then(res => {
if (res && res.data && res.data.code === 200) {
onSure(res.data.msg);
}
}).finally(() => { setLoading(false) });
}
});
}
function closeHandler() {
// form.resetFields();
onCancel();
}
return(
<Modal
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={closeHandler}></i>}
className="qa_modal"
visible={visible}
title={<div className="title_box">
<img alt="头像" src={IconImg} style={{width: '48px', height: '48px'}}></img>
<div className="txt">
<h4>
线下参观/沙龙报名
</h4>
<p>{zoneName}<span> · </span>线下参观/沙龙报名</p>
</div>
</div>}
closable={true}
width={672}
footer={
<div>
<Button onClick={closeHandler}>取消</Button>
<Button className="btn_ok" style={{marginLeft:"20px"}} onClick={onOk} loading={loading}>确定</Button>
</div>
}
okText="确定"
cancelText="取消"
>
<div className="info">
<div className="tipsline">
<i className="iconfont icon-shanchu_tc_icon1"></i>
<div style={{flex: 1}}>
<p>申请将冻结对应积分服务达成后正式扣除若关闭申请积分将退回</p>
</div>
</div>
<Form form={form}>
<Row gutter={40}>
<Col span={12}>
<Form.Item label="真实姓名">
{getFieldDecorator('realName', {
rules: [
{
required: true,
message: '请输入真实姓名'
}
],
})(
<Input placeholder="请输入真实姓名" maxLength={20} />,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="联系电话">
{getFieldDecorator('phone', {
rules: [
{
required: true,
message: '请输入联系电话'
}
],
})(
<Input placeholder="请输入联系电话" maxLength={20} />,
)}
</Form.Item>
</Col>
</Row>
<Form.Item label="诉求简述">
{getFieldDecorator('description')(
<TextArea maxLength={200} placeholder="请简述您的诉求" autoSize={{ minRows: 3, maxRows: 3 }} showcount="true" />,
)}
</Form.Item>
<Form.Item label="所属单位">
{getFieldDecorator('organization')(
<Input placeholder="请输入所属单位" maxLength={50} />,
)}
</Form.Item>
<Row gutter={40}>
<Col span={12}>
<Form.Item label="微信号">
{getFieldDecorator('wechat')(
<Input placeholder="请输入微信号" maxLength={30} />,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="邮箱">
{getFieldDecorator('email')(
<Input placeholder="请输入邮箱" maxLength={50} />,
)}
</Form.Item>
</Col>
</Row>
</Form>
</div>
</Modal>
)
}
export default Form.create()(ApplyActivity);

View File

@ -0,0 +1,133 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Button, Row, Col } from 'antd';
import { doApplyQA } from '../api';
const { TextArea } = Input;
import IconImg from '../img/user/icon1.png';
import '../indexUser.scss';
function ApplyQA({ visible, onCancel, onSure, form, member, zoneName }) {
const [loading, setLoading] = useState(false);
const { getFieldDecorator, validateFields } = form;
useEffect(() => {
if (visible) {
}
}, [visible]);
function onOk() {
validateFields((err, values) => {
if (!err) {
setLoading(true);
const data = Object.assign({}, values, { zoneId: member.zoneId });
doApplyQA(data).then(res => {
if (res && res.data && res.data.code === 200) {
onSure(res.data.msg);
}
}).finally(() => { setLoading(false) });
}
});
}
function closeHandler() {
// form.resetFields();
onCancel();
}
return(
<Modal
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={closeHandler}></i>}
className="qa_modal"
visible={visible}
title={<div className="title_box">
<img alt="头像" src={IconImg} style={{width: '48px', height: '48px'}}></img>
<div className="txt">
<h4>
专家一对一答疑
</h4>
<p>{zoneName}<span> · </span>专家一对一答疑</p>
</div>
</div>}
closable={true}
width={672}
footer={
<div>
<Button onClick={closeHandler}>取消</Button>
<Button className="btn_ok" style={{marginLeft:"20px"}} onClick={onOk} loading={loading}>确定</Button>
</div>
}
okText="确定"
cancelText="取消"
>
<div className="info">
<div className="tipsline">
<i className="iconfont icon-shanchu_tc_icon1"></i>
<div style={{flex: 1}}>
<p>申请将冻结对应积分服务达成后正式扣除若关闭申请积分将退回</p>
</div>
</div>
<Form form={form}>
<Row gutter={40}>
<Col span={12}>
<Form.Item label="真实姓名">
{getFieldDecorator('realName', {
rules: [
{
required: true,
message: '请输入真实姓名'
}
],
})(
<Input placeholder="请输入真实姓名" maxLength={20} />,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="联系电话">
{getFieldDecorator('phone', {
rules: [
{
required: true,
message: '请输入联系电话'
}
],
})(
<Input placeholder="请输入联系电话" maxLength={20} />,
)}
</Form.Item>
</Col>
</Row>
<Form.Item label="诉求简述">
{getFieldDecorator('description')(
<TextArea maxLength={200} placeholder="请简述您的诉求" autoSize={{ minRows: 3, maxRows: 3 }} showcount="true" />,
)}
</Form.Item>
<Form.Item label="所属单位">
{getFieldDecorator('organization')(
<Input placeholder="请输入所属单位" maxLength={50} />,
)}
</Form.Item>
<Row gutter={40}>
<Col span={12}>
<Form.Item label="微信号">
{getFieldDecorator('wechat')(
<Input placeholder="请输入微信号" maxLength={30} />,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="邮箱">
{getFieldDecorator('email')(
<Input placeholder="请输入邮箱" maxLength={50} />,
)}
</Form.Item>
</Col>
</Row>
</Form>
</div>
</Modal>
)
}
export default Form.create()(ApplyQA);

View File

@ -1,16 +1,36 @@
import React,{useCallback, useEffect,useState} from 'react';
import React,{useCallback, useEffect,useState,useMemo,useRef} from 'react';
import { Link } from 'react-router-dom';
import { tempEnum } from '../tempInfo';
import Crown from '../img/crown.png';
import Nodata from '../../Nodata';
import nodata from '../img/nodata.png';
import { Input } from 'antd';
import Slider from 'react-slick';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import Left from '../img/ringleft.png';
import Right from '../img/ringright.png';
const { Search } = Input;
function Member(props) {
const { vipLists, temp , deptId , headIcon , hoverIcon } = props;
const isUOS = deptId === "uos";//id===91:
const [ list , setList ] = useState(vipLists);
const sliderRef = useRef(null);
const [currentSlide, setCurrentSlide] = useState(0);
// 8
const groupMembersByRow = (members) => {
if (!members || members.length === 0) return [];
const grouped = [];
for (let i = 0; i < members.length; i += 24) {
grouped.push(members.slice(i, i + 24));
}
console.log(grouped);
return grouped;
};
useEffect(()=>{
if(vipLists && vipLists.length > 0 ){
@ -30,6 +50,51 @@ function Member(props) {
setList(ele);
}
const PrevArrow = (props) => {
const { onClick } = props;
const isDisabled = currentSlide === 0;
return (
<span
onClick={isDisabled ? undefined : onClick}
className={`custom-prev-arrow ${isDisabled ? 'arrow-disabled' : ''}`}
>
<i className="iconfont-color icon-colorzuojiantou" />
</span>
);
};
const NextArrow = (props) => {
const { onClick, currentSlide, slideCount } = props;
const isDisabled = currentSlide >= slideCount - 1;
return (
<span
onClick={isDisabled ? undefined : onClick}
className={`custom-next-arrow ${isDisabled ? 'arrow-disabled' : ''}`}
>
<i className="iconfont-color icon-coloryoujiantou" />
</span>
);
};
const cateSetting={
dots: false,
arrows: true,
infinite: false,
speed: 800,
slidesToShow: 1,
slidesToScroll: 1,
centerMode: false,
centerPadding: '0px',
autoplay: false,
autoplaySpeed: 5000,
pauseOnHover: true,
prevArrow: <PrevArrow />,
nextArrow: <NextArrow />,
afterChange: (index) => {
setCurrentSlide(index);
},
}
return(
<div className="vip_list">
{
@ -60,13 +125,38 @@ function Member(props) {
}
{
i.zoneMemberList && i.zoneMemberList.length > 0 ?
<ul className={`card_ul ${isUOS && i.id === 91 ? "doubleUl" :""}`}>
(i.typeName.indexOf("社区成员")>-1 && !deptId ?
<div>
<span className='totalMemeber'>成员总览<span>{i.zoneMemberList.length}</span></span>
<Slider ref={sliderRef} {...cateSetting} className='memeberSlider'>
{
groupMembersByRow(i.zoneMemberList).map((row, rowIndex) => (
<div>
<div key={rowIndex} className='zoneMemberRow'>
{row.map((member, colIndex) => (
<div key={member.login + colIndex} className='zoneMemberItem'>
<div className='zoneMI_box'>
<div className='zoneMI_img'>
<Link to={`/${member.login}`} ><img src={member.imageUrl} alt="" width={80} height={80}/></Link>
</div>
<div className='zoneMI_name task-hide' title={member.name}>{member.name}</div>
<div>{member.memberLevel && <span className="card_tag">{member.memberLevel}</span> }</div>
</div>
</div>
))}
</div>
</div>
))
}
</Slider>
</div>
: <ul className={`card_ul ${isUOS && i.id === 91 ? "doubleUl" :""}`}>
{
i.zoneMemberList.map((j,key)=>{
return(
<li className="card_u_li">
<Link to={`/${j.login}`} className="card_u_wrap">
{ !(isUOS && i.id === 91) && <Link to={`/${j.login}`} ><img src={j.imageUrl} alt="" /></Link> }
{ !(isUOS && i.id === 91) && <Link to={`/${j.login}`} ><img src={j.imageUrl} alt=""/></Link> }
<div className="card_u_info">
<div className="card_u_up">
<span className="card_name task-hide">{j.name}</span>
@ -81,10 +171,9 @@ function Member(props) {
})
}
</ul>
:
(
temp === tempEnum.zone1 ? <Nodata _html="暂无数据" img={ nodata }/> : <Nodata _html="暂无数据" />
)
:
(temp === tempEnum.zone1 ? <Nodata _html="暂无数据" img={ nodata }/> : <Nodata _html="暂无数据" />)
}
</div>
)

View File

@ -0,0 +1,142 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Button, Spin, Pagination } from 'antd';
import Nodata from '../../Nodata';
import { getNewsMyList, getMyTopArticle, doDocTop } from '../api';
const { TextArea } = Input;
import { getImageUrl } from 'educoder'
import '../indexUser.scss';
function PointsDoc({ visible , onCancel , onSure , type , username , choosed , history , showCompeleteDialog , member }) {
const limit = 5;
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(0);
const [ isSpin , setIsSpin ] = useState(true);
const [ list , setList ] = useState(undefined);
const [ currentId , setCurrentId ] = useState(null);
const [ currentRow , setCurrentRow ] = useState(null);
useEffect(()=>{
if(visible && member) {
setPage(1);
}
},[visible, member])
useEffect(()=>{
if(visible && member) {
init();
}
},[visible, member])
useEffect(()=>{
if(visible && member) {
getMyNews();
}
},[page])
async function init() {
setIsSpin(true);
try{
let res = await getMyTopArticle(member.zoneId);
if(res && res.data.code === 200){
setCurrentRow(res.data.data);
let newId = null;
if(res.data.data) {
newId = res.data.data.docId;
}
setCurrentId(newId);
await getMyNews(newId);
}
}finally{
setIsSpin(false)
}
}
async function getMyNews(overrideId){
const excludeId = overrideId !== undefined ? overrideId : currentId;
let result = await getNewsMyList(member.zoneId,{auditStatus:1, excludeId, pageSize:limit, pageNum:page});
let rows = result.data && result.data.rows;
if(rows && rows.length>0){
setList(rows);
}else{
setList([]);
}
setTotal(result.data.total);
}
function onOk() {
}
async function handlePin(item) {
setIsSpin(true);
try {
let data = Object.assign({}, item, {zoneId: member.zoneId});
await doDocTop(data);
onSure();
} finally {
setIsSpin(false);
}
}
return(
<Modal
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={onCancel}></i>}
className="doc_modal"
visible={visible}
title={<div className="title_box">
专区首页新闻推荐
</div>}
closable={true}
width={800}
footer={
<div>
<Button onClick={onCancel}>关闭</Button>
</div>
}
okText="确定"
cancelText="取消"
>
<div className="info">
<Spin spinning={isSpin}>
<div className="line topline">
<span className="content">新闻标题</span>
<span className="action">操作</span>
</div>
{currentRow && (
<div className="line dataline">
<span className="content">{currentRow.docName}</span>
<span className="action">
<Button type="primary" shape="round" disabled style={{backgroundColor:'rgba(70, 106, 255, 0.43)', borderColor:'rgba(70, 106, 255, 0.43)', color:'#fff'}}>已置顶</Button>
</span>
</div>
)}
{list && list.map((item) => (
<div className="line dataline" key={item.id}>
<span className="content">{item.name}</span>
<span className="action">
<Button type="primary" shape="round" disabled={!!currentRow} onClick={() => handlePin(item)}>置顶</Button>
</span>
</div>
))}
{ !isSpin && !currentId && (!list || !list.length) && <Nodata _html="暂无数据" />
}
</Spin>
{
total > limit &&
<div style={{padding:"20px",textAlign:"right"}}>
<Pagination showQuickJumper current={page} total={total} pageSize={limit} onChange={(p)=>{setPage(p);}}/>
</div>
}
</div>
</Modal>
)
}
export default PointsDoc;

View File

@ -0,0 +1,142 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Button, Spin, Pagination } from 'antd';
import Nodata from '../../Nodata';
import { getProjectMyList, getMyTopProject, doProjectTop } from '../api';
const { TextArea } = Input;
import { getImageUrl } from 'educoder'
import '../indexUser.scss';
function PointsDoc({ visible , onCancel , onSure , type , username , choosed , history , showCompeleteDialog , member }) {
const limit = 5;
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(0);
const [ isSpin , setIsSpin ] = useState(true);
const [ list , setList ] = useState(undefined);
const [ currentId , setCurrentId ] = useState(null);
const [ currentRow , setCurrentRow ] = useState(null);
useEffect(()=>{
if(visible && member) {
setPage(1);
}
},[visible, member])
useEffect(()=>{
if(visible && member) {
init();
}
},[visible, member])
useEffect(()=>{
if(visible && member) {
getMyProject();
}
},[page])
async function init() {
setIsSpin(true);
try{
let res = await getMyTopProject(member.zoneId);
if(res && res.data.code === 200){
setCurrentRow(res.data.data);
let newId = null;
if(res.data.data) {
newId = res.data.data.id;
}
setCurrentId(newId);
await getMyProject(newId);
}
}finally{
setIsSpin(false)
}
}
async function getMyProject(overrideId){
const excludeId = overrideId !== undefined ? overrideId : currentId;
let result = await getProjectMyList({zoneId: member.zoneId, auditStatus:1, excludeId, pageSize:limit, pageNum:page});
let rows = result.data && result.data.rows;
if(rows && rows.length>0){
setList(rows);
}else{
setList([]);
}
setTotal(result.data.total);
}
function onOk() {
}
async function handlePin(item) {
setIsSpin(true);
try {
let data = Object.assign({}, item, {zoneId: member.zoneId});
await doProjectTop(data);
onSure();
} finally {
setIsSpin(false);
}
}
return(
<Modal
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={onCancel}></i>}
className="doc_modal"
visible={visible}
title={<div className="title_box">
专区首页项目推荐
</div>}
closable={true}
width={800}
footer={
<div>
<Button onClick={onCancel}>关闭</Button>
</div>
}
okText="确定"
cancelText="取消"
>
<div className="info">
<Spin spinning={isSpin}>
<div className="line topline">
<span className="content">项目名称</span>
<span className="action">操作</span>
</div>
{currentRow && (
<div className="line dataline">
<span className="content">{currentRow.name}</span>
<span className="action">
<Button type="primary" shape="round" disabled style={{backgroundColor:'rgba(70, 106, 255, 0.43)', borderColor:'rgba(70, 106, 255, 0.43)', color:'#fff'}}>已置顶</Button>
</span>
</div>
)}
{list && list.map((item) => (
<div className="line dataline" key={item.id}>
<span className="content">{item.projectProperties?.name}</span>
<span className="action">
<Button type="primary" shape="round" disabled={!!currentRow} onClick={() => handlePin(item)}>置顶</Button>
</span>
</div>
))}
{ !isSpin && !currentId && (!list || !list.length) && <Nodata _html="暂无数据" />
}
</Spin>
{
total > limit &&
<div style={{padding:"20px",textAlign:"right"}}>
<Pagination showQuickJumper current={page} total={total} pageSize={limit} onChange={(p)=>{setPage(p);}}/>
</div>
}
</div>
</Modal>
)
}
export default PointsDoc;

View File

@ -11,10 +11,9 @@ import uosIcon from "../img/uos.png";
const { Search } = Input;
function PublicBanner(props) {
const [key, setKey] = useState("1");
const { deptId } = props.match.params;
const { pathname } = props.history.location;
const { data: { sectionHomepageShow, sectionHomepageTitle, sectionProjectShow, sectionDataSetShow, sectionDataSetTitle, sectionProjectTitle, sectionResourceShow, sectionResourceTitle, sectionCmsShow, sectionCmsTitle, sectionMemberShow, sectionMemberTitle, sectionHelperShow, sectionHelperTitle }, data, adminUrl, temp, showLoginDialog, showNotification, checkIfLogin, id } = props;
const { data: { sectionHomepageShow, sectionHomepageTitle, sectionProjectShow, sectionDataSetShow, sectionDataSetTitle, sectionProjectTitle, sectionResourceShow, sectionResourceTitle, sectionCmsShow, sectionCmsTitle, sectionMemberShow, sectionPointsShow, sectionMemberTitle, sectionHelperShow, sectionHelperTitle }, data, adminUrl, temp, showLoginDialog, showNotification, checkIfLogin, id } = props;
const isNSCC = deptId === "NSCC";
const isUOS = deptId === "uos";
const [memberStatus, setMemberStatus] = useState(memberStatusEnum.notMember);
@ -27,41 +26,21 @@ function PublicBanner(props) {
return Boolean(sectionHomepageShow | sectionProjectShow | sectionDataSetShow | sectionResourceShow | sectionCmsShow | sectionMemberShow | sectionHelperShow | adminUrl)
}, [sectionHomepageShow, sectionProjectShow, sectionDataSetShow, sectionResourceShow, sectionCmsShow, sectionMemberShow, sectionHelperShow, adminUrl])
useEffect(() => {
if (pathname) {
const info = /[A-Za-z0-9]{0,}\/news/g;
const infodetail = /[A-Za-z0-9]{0,}\/newdetail/g;
const project = /[A-Za-z0-9]{0,}\/projects/g;
const source = /[A-Za-z0-9]{0,}\/source/g;
const vip = /[A-Za-z0-9]{0,}\/VIP/g;
const help = /[A-Za-z0-9]{0,}\/help/g;
const dataset = /[A-Za-z0-9]{0,}\/dataset/g;
const lesson = /[A-Za-z0-9]{0,}\/lessons/g;
if (pathname === `/zone/${deptId}`) {
setKey("1");
}
else if (project.test(pathname)) {
setKey("2");
}
else if (source.test(pathname)) {
setKey("3");
}
else if (info.test(pathname) || infodetail.test(pathname)) {
setKey("4");
}
else if (vip.test(pathname)) {
setKey("6");
}
else if (help.test(pathname)) {
setKey("8");
}
else if (dataset.test(pathname)) {
setKey("9");
}else if(lesson.test(pathname)) {
setKey("10");
}
const key = useMemo(() => {
if (!pathname) return "1";
if (pathname === `/zone/${deptId}`) return "1";
if (/[A-Za-z0-9]{0,}\/projects/g.test(pathname)) return "2";
if (/[A-Za-z0-9]{0,}\/source/g.test(pathname)) return "3";
if (/[A-Za-z0-9]{0,}\/(news|newdetail)/g.test(pathname)) return "4";
if (/[A-Za-z0-9]{0,}\/VIP/g.test(pathname)) return "6";
if (/[A-Za-z0-9]{0,}\/help/g.test(pathname)) return "8";
if (/[A-Za-z0-9]{0,}\/dataset/g.test(pathname)) return "9";
if (/[A-Za-z0-9]{0,}\/lessons/g.test(pathname)) return "10";
if (/[A-Za-z0-9]{0,}\/(user|score)/gi.test(pathname)) {
return (!adminUrl && sectionPointsShow) ? "11" : "1";
}
}, [pathname])
return "1";
}, [pathname, deptId, adminUrl, sectionPointsShow])
useEffect(() => {
if (id && deptId && deptId === "NSCC") {
@ -187,6 +166,7 @@ function PublicBanner(props) {
{/* <Menu.Item key={"5"}><img src={Menu5} alt="" width="27px"/>Sig小组</Menu.Item> */}
{isNSCC && <Menu.Item key={"10"}><a onClick={toLessonsFunc}><img src={require(`../img/${temp}Menu10.png`)} alt="" width="36px" />课程实训</a></Menu.Item>}
{sectionMemberShow && <Menu.Item key={"6"}><Link to={`/zone/${deptId}/VIP`}><img src={require(`../img/${temp}Menu6.png`)} alt="" width="36px" />{sectionMemberTitle}</Link></Menu.Item>}
{(!adminUrl && sectionPointsShow) && <Menu.Item key={"11"}><Link to={`/zone/${deptId}/user`}><img src={require(`../img/user/${temp}Menu11.png`)} alt="" width="36px" />积分中心</Link></Menu.Item>}
{sectionHelperShow && <Menu.Item key={"8"}><Link to={`/zone/${deptId}/help`}><img src={require(`../img/${temp}Menu8.png`)} alt="" width="36px" />{data.sectionHelperTitle}</Link></Menu.Item>}
{adminUrl && <Menu.Item key={"7"}><a onClick={() => { window.location.href = adminUrl }}><img src={require(`../img/${temp}Menu7.png`)} alt="" width="34px" />后台管理</a></Menu.Item>}
</Menu>

View File

@ -13,13 +13,18 @@
font-family: 'alibaba PuHuiTi';
background-image: url(../../img/custom/bc.png);
background-size: 100%;
.statistics-cards-bc{
background-image: url(../../img/vipTitleBc.png);
background-size: 100% 124%;
padding: 25px 0;
background-position-y: bottom;
}
.statistics-cards{
width: 80%;
margin: 25px auto;
margin: 0 auto;
text-align: center;
border: 2px solid #ffffff;
border-radius: 15px;
background: rgba(255, 255, 255, 0.2352941176);
backdrop-filter: blur(10px);
padding: 30px 0;
color:#091221;

View File

@ -27,8 +27,7 @@ function CustomVip(props){
const [ applyVisible , setApplyVisible ] = useState(false);
const [ memberStatus , setMemberStatus] = useState(memberStatusEnum.notMember);
const { id, showNotification, checkIfLogin, showLoginDialog, temp, sectionMemberTitle } = props;
const isNSCC = deptId === "NSCC";
useEffect(()=>{
let uuid = getUniqueIdentifier()
let url = props.location.pathname
@ -50,7 +49,7 @@ function CustomVip(props){
function getLists(){
getVIPLists(id).then(response=>{
if(response){
if(response && response.data){
setVIPLists(response.data.rows);
setIsSpin(false);
}
@ -86,19 +85,27 @@ function CustomVip(props){
}
setApplyVisible(!applyVisible)
}
const nsccTitle = (title, delay=0.1, classname)=> <div className={`project-cate-title fadeInChar ${classname}`}>
{title && title.split("").map((char, index) => (
<span key={index} className="title-char" style={{ animationDelay: `${delay + index * 0.1}s` }}>
{char}
</span>
))}
const nsccTitle = (title, delay = 0.1, classname, emptyIndex) => <div className={`project-cate-title fadeInChar ${classname}`}>
{title && title.split("").map((char, index) => {
return (
<>
<span key={index} className="title-char" style={{ animationDelay: `${delay + index * 0.1}s` }}>
{char}
</span>
{emptyIndex && index === emptyIndex - 1 && <span className="title-char" style={{ width: "20px" }}></span>}
</>
)
}
)}
</div>
return(
<div className='customvipBox customPublic'>
<MemberApply visible={applyVisible} onOk={ onOk } onCancel={() => setApplyVisible(!applyVisible)} current_user={props.current_user}/>
<div className={`width1600`}>
{ nsccTitle(sectionMemberTitle) }
<div className="statistics-cards">{tempConfig[temp].vipDesc}</div>
{ nsccTitle(`社区会员` + "聚力前行", 0.1, "", 4) }
<div className="statistics-cards-bc">
<div className="statistics-cards">{tempConfig[temp].vipDesc}</div>
</div>
<div className='applyCards'>
{ memberStatus === memberStatusEnum.notMember && <GlowButton onClick={ apply } className="NSCC_project_btn blue_image font-15">申请加入<i className='iconfont icon-arrowRight font-16 ml5'></i></GlowButton>}
{ memberStatus === memberStatusEnum.applying && <div className="tips font-15"><Icon type="check-circle" theme="filled" className="mr5"/>您的申请已提交请耐心等待管理员审核!</div> }

View File

@ -1,6 +1,6 @@
import React , { useEffect, useRef, useState } from 'react';
import { Link } from 'react-router-dom';
import { getDirListById, getSubDocList } from '../../../api';
import { getDirListById, getSubDocList, getPointsDocList } from '../../../api';
import { Badge, Col, Divider, Icon, Row } from 'antd';
import '../index.scss';
import Nodata from '../../../../Nodata';
@ -19,6 +19,11 @@ function News(props) {
const [activeDirId, setActiveDirId] = useState(undefined);
const [total, setTotal] = useState(0);
const newsSectionRef = useRef(null);
const topBoxRef = useRef(null);
const [hasAppended, setHasAppended] = useState(false);
const [activeIndex, setActiveIndex] = useState(0);
const scrollIndexRef = useRef(0);
const scrollTimerRef = useRef(null);
useEffect(() => {
let hasAnimated = false; //
@ -60,11 +65,8 @@ function News(props) {
rows[0] && getDocById(rows[0].id, 5, (data)=>{
setDocListByFirstDir(data)
})
// 23
rows[1] && getDocById(rows[1].id, 3, (data)=>{
setDocListBySecondDir(data)
})
// rows[2] && setActiveDirId(rows[2].id)
getPointsDoc();
}
})
}, [id])
@ -74,6 +76,97 @@ function News(props) {
setDocListByDir(data)
}, (data)=>{setTotal(data)})
}, [activeDirId])
// topBox>593docListBySecondDir
useEffect(() => {
if (!topBoxRef.current || !docListBySecondDir.length) return;
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const height = entry.contentRect.height;
if (height > 593 && !hasAppended) {
setDocListBySecondDir(prev => [...prev, ...docListBySecondDir]);
setHasAppended(true);
// hasAppendeduseEffect
}
}
});
observer.observe(topBoxRef.current);
return () => {
observer.disconnect();
};
}, [docListBySecondDir, hasAppended])
// 3docBySecondDir_NSCCtopBox
useEffect(() => {
if (!hasAppended || !topBoxRef.current) return;
const topBox = topBoxRef.current;
scrollIndexRef.current = 0;
// topBoxtransition
topBox.style.transition = 'transform 0.5s linear';
scrollTimerRef.current = setInterval(() => {
const items = topBox.querySelectorAll('.docBySecondDir_NSCC');
if (!items.length) return;
const targetIndex = scrollIndexRef.current % items.length;
// margintranslateY
let offset = 0;
for (let i = 0; i < targetIndex; i++) {
offset += items[i].offsetHeight;
const styles = window.getComputedStyle(items[i]);
offset += parseFloat(styles.marginBottom) || 0;
}
topBox.style.transform = `translateY(-${offset}px)`;
// offset0
if (targetIndex === docListBySecondDir.length / 2) {
setActiveIndex((targetIndex + 1) % (docListBySecondDir.length / 2));
setTimeout(() => {
topBox.style.transition = 'none';
topBox.style.transform = 'translateY(0)';
void topBox.offsetWidth;
topBox.style.transition = 'transform 0.5s linear';
setActiveIndex(1);
}, 500);
scrollIndexRef.current = 0;
} else {
setActiveIndex((targetIndex + 1) % (docListBySecondDir.length / 2));
}
scrollIndexRef.current++;
}, 3000);
return () => {
if (scrollTimerRef.current) {
clearInterval(scrollTimerRef.current);
scrollTimerRef.current = null;
}
// topBox
topBox.style.transition = '';
topBox.style.transform = '';
};
}, [hasAppended])
function getPointsDoc() {
getPointsDocList(id).then(result=>{
let docList = [];
if(result && Array.isArray(result.data.data) && result.data.data.length){
docList = result.data.data.map(item => {
item.id = item.docId;
item.name = item.docName;
item.summary = item.summary;
item.zoneId = item.zoneId;
return item;
});
}
setDocListBySecondDir(docList);
});
}
// id
function getDocById(dirId, pageSize=10, setData, setTotal1){
@ -114,21 +207,33 @@ function News(props) {
</div>}
</div>}
{/* 第二个顺序栏目 */}
{secondDir && <div className='secondDir_NSCC flex1 ml30'>
<Divider type="vertical" style={{width: '3px', height: '17px', backgroundColor: "#466aff", marginBottom: '5px'}}/>
<Link to={`/zone/${key}/news/${secondDir.id}`} onClick={()=>{window.scrollTo(0,450)}} className="font-18 font-bd">{secondDir.name}</Link>
{docListBySecondDir.map(item=>{
return <div className='docBySecondDir_NSCC mt15'>
<p className='font-16 font-bd task-hide'>
<Link to={`/zone/${key}/newdetail/${item.id}`} onClick={()=>{window.scrollTo(0,450)}}>{item.name}</Link>
</p>
<div className='color5d6 font-14 mt5 mb12 task-hide-2'>
{item.summary}
{secondDir && <div className='secondDir_NSCC flex1 ml20'>
{/* <Divider type="vertical" style={{width: '3px', height: '17px', backgroundColor: "#466aff", marginBottom: '5px'}}/> */}
{/* <Link to={`/zone/${key}/news/${secondDir.id}`} onClick={()=>{window.scrollTo(0,450)}} className="font-18 font-bd">{secondDir.name}</Link> */}
<div style={{
overflow: 'hidden',
height: '593px',
...(hasAppended ? {
WebkitMaskImage: 'linear-gradient(to bottom, transparent 0%, black 60px, black calc(100% - 60px), transparent 100%)',
maskImage: 'linear-gradient(to bottom, transparent 0%, black 60px, black calc(100% - 60px), transparent 100%)'
} : {})
}}>
<div className='topBox' ref={topBoxRef}>
{docListBySecondDir.map((item, index)=>{
return <div className={`docBySecondDir_NSCC ${index % (docListBySecondDir.length / 2) === activeIndex ? 'active' : ''}`}>
<p className='font-16 font-bd task-hide'>
<Link to={`/zone/${key}/newdetail/${item.id}`} onClick={()=>{window.scrollTo(0,450)}}>{item.name}</Link>
</p>
<div className='color5d6 font-14 mt5 mb12 task-hide-2'>
{item.summary}
</div>
<Link to={`/zone/${key}/newdetail/${item.id}`} className="font-14">查看详情<i className='iconfont icon-jiantou21 font-12 ml5'></i></Link>
</div>
<Link to={`/zone/${key}/newdetail/${item.id}`} className="font-14">查看详情<i className='iconfont icon-jiantou21 font-12 ml5'></i></Link>
})}
</div>
})}
{docListBySecondDir && !docListBySecondDir.length && <div style={{margin: '0 auto', maxHeight: '230px'}}><Nodata small _html="暂无数据"/></div>}
{docListBySecondDir && !docListBySecondDir.length && <div style={{margin: '0 auto', maxHeight: '230px'}}><Nodata small _html="暂无数据"/></div>}
</div>
</div>}
</div>
</div>

View File

@ -1,6 +1,6 @@
import React, { useEffect, useRef, useState } from 'react';
import '../index.scss';
import { getProjectListByScore, getProjectsTypeLists } from '../../../api';
import { getProjectListByScore, getProjectsTypeLists, getPointsProjectList } from '../../../api';
import { Carousel, Divider, Pagination, Spin } from 'antd';
import Nodata from '../../../../Nodata';
import Slider from 'react-slick';
@ -24,6 +24,7 @@ function TypeCarousel({pageSize=4, list=[], typeId, onClick}) {
{page.map((item, i) => {
const order = index*pageSize+i
const iconName = {
"精选项目": "icon-jingxuanxiangmu1",
"并行计算框架": "icon-binghangjisuankuangjia",
"异构数据库": "icon-yigoushujuku",
"性能基准与评测": "icon-xingnengjizhunyupingce",
@ -55,6 +56,7 @@ function Project({ data, nsccTitle }) {
const [typeList, setTypeList] = useState([]);
const [typeId, setTypeId] = useState(undefined);
const [lists, setLists] = useState([]);
const [topList, setTopList] = useState([]);
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
@ -93,20 +95,41 @@ function Project({ data, nsccTitle }) {
}, []);
useEffect(() => {
id && getProjectsTypeLists(id, {
pageNum: 1,
pageSize: 100,
}).then(result => {
if (result) {
const rows = result.data.rows;
rows[0] && setTypeId(rows[0].id)
setTypeList(rows);
async function fetchTypeData() {
let typeList = [];
let typeId = null;
if(id) {
let res = await getPointsProjectList(id);
if(res && Array.isArray(res.data.data) && res.data.data.length){
setTopList(res.data.data);
typeList.push({id: -1, zoneId: id, name: '精选项目'});
typeId = -1;
}
getProjectsTypeLists(id, {
pageNum: 1,
pageSize: 100,
}).then(result => {
if (result) {
const rows = result.data.rows;
if(Array.isArray(rows) && rows.length) {
typeList = [...typeList, ...rows];
setTypeList(typeList);
if (typeId === null) {
setTypeId(rows[0].id);
} else {
setTypeId(typeId);
}
}
}
}).catch(() => { })
}
}).catch(() => { })
}
fetchTypeData();
}, [id])
useEffect(() => {
if (typeId) {
if (typeId && typeId !== -1) { //
setLoading(true);
getProjectListByScore(id, {
pageNum: page,
@ -168,25 +191,86 @@ function Project({ data, nsccTitle }) {
</div>
}
const topDetail = (className="top_detail", i, index, length) => {
const { extra: { } } = i || {}
return <div className={`${className} ${className === "second_detail" && index <3 && index<length-1 && 'pb30'} ${(index === length && index%3 === 0) && 'noBor'}`} key={i.id} onClick={() => window.open(i.projectURL)}>
<div className='clearfix'>
<span className='topTitle'>{i.projectProperties && i.projectProperties.name}</span>
</div>
<div className="task-hide-2 mt5 mb12">
{i.projectProperties.description || "暂无描述"}
</div>
<div style={{ minHeight: 46 }}>
<ul className="top_tag_NSCC pb15 df wrap">
{
i.projectProperties && i.projectProperties.topics &&
i.projectProperties.topics.split(",").map(t => {
return (
<li className='font-13 mt5'>{t}</li>
)
})
}
</ul>
</div>
<p className='df between baseline'>
<div className='df font-15 font-bd' style={{alignItems: 'center'}}>
{i.projectProperties.language && (
<>
<div className='pythonicon'></div>
<span className='mr5 font-14 font-n'>{i.projectProperties.language}</span>
<Divider type="vertical" style={{ margin: '0 15px' }} />
</>
)}
{i.projectProperties.timeAgo && <span className='mr5 font-14 font-n'>更新于{i.projectProperties.timeAgo}</span>}
</div>
<div>
<span className='topitem mr10'><i className="iconfont icon-xingzhuang mr3 font-14" style={{color: '#d18733'}}></i> {i.projectProperties.praisesCount}</span>
<span className='topitem'><i className="iconfont icon-yifuke_icon mr3 font-14" style={{color: '#5545bd'}}></i> fork {i.projectProperties.forkedCount}</span>
</div>
</p>
</div>
}
return <div className='project_1_bg_NSCC viewEntry' id="nscc_home4" ref={newsSectionRef}>
<div className='project_1 width1600 pt50 pb60'>
{nsccTitle(homepageProjectTitle, 0.1, "font-bd font-30 mb50 align task-hide")}
<div className='project_list_NSCC'>
<TypeCarousel pageSize={10} list={typeList} typeId={typeId} onClick={(id)=>{setTypeId(id); setPage(1)}}/>
<Spin spinning={loading}>
<div className='df gap20'>
{lists.slice(0, 3).map((i, index)=>{
return projectDetail("online_detail", i, index, 3)
})}
</div>
{lists.length > 3 && <div className='df second_detailBox mt30 wrap'>
{lists.slice(3).map((i, index)=>{
return projectDetail("second_detail", i, index, lists.slice(4).length)
})}
</div>}
<Pagination pageSize={9} total={total} hideOnSinglePage={true} current={page} onChange={(page)=>{setPage(page)}} className='center mt30'/>
{!loading && lists.length === 0 && <Nodata _html="暂无数据" />}
</Spin>
{
typeId !== -1 &&
<Spin spinning={loading}>
<div className='df gap20'>
{lists.slice(0, 3).map((i, index)=>{
return projectDetail("online_detail", i, index, 3)
})}
</div>
{lists.length > 3 && <div className='df second_detailBox mt30 wrap'>
{lists.slice(3).map((i, index)=>{
return projectDetail("second_detail", i, index, lists.slice(4).length)
})}
</div>}
<Pagination pageSize={9} total={total} hideOnSinglePage={true} current={page} onChange={(page)=>{setPage(page)}} className='center mt30'/>
{!loading && lists.length === 0 && <Nodata _html="暂无数据" />}
</Spin>
}
{
typeId === -1 &&
<Spin spinning={loading}>
<div className='df gap20'>
{topList.slice(0, 3).map((i, index)=>{
return topDetail("top_detail", i, index, 3)
})}
</div>
{topList.length > 3 && <div className='top_detailBox mt20'>
{topList.slice(3).map((i, index)=>{
return topDetail("top_detail", i, index, topList.slice(4).length)
})}
</div>}
{/* <Pagination pageSize={9} total={total} hideOnSinglePage={true} current={page} onChange={(page)=>{setPage(page)}} className='center mt30'/> */}
{!loading && topList.length === 0 && <Nodata _html="暂无数据" />}
</Spin>
}
</div>
</div>
</div>

View File

@ -56,9 +56,9 @@ function Source({data, nsccTitle}) {
</div>
<Spin spinning={isSpin} style={{minHeight: '300px'}}>
<div className='df wrap gap20 fadeUpNSCCHome'>
{sourceList.map(i => {
{sourceList.map((i, index) => {
const time = i.updateTime || i.createTime
return <div className='s_1_souce_NSCC mt30'>
return <div className={`s_1_souce_NSCC ${index < 3 ? 'mt30' : ''}`}>
<Link to={`/zone/${key}/source/${i.id}`}>
<div className='flexCenter between'>
<span className='souce_icon_box'>

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

View File

@ -829,7 +829,7 @@
}
}
.firstDir_NSCC{
width:690px;
width:910px;
background-color: #F6F8FD;
border-radius:15px;
box-shadow:0px 0px 12px rgba(33, 73, 212, 0.1);
@ -875,7 +875,7 @@
}
.firstDoc_Img{
width:690px;
width:910px;
object-fit: cover;
transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
@ -894,17 +894,26 @@
background: linear-gradient(180deg,#f4f7ff 0%,#F6F8FD 100%), url('./image/bkImg6.png') top/contain no-repeat;
background-blend-mode: multiply;
padding: 30px 25px;
max-height:653px;
overflow: hidden;
}
.topBox{
}
.docBySecondDir_NSCC{
cursor: pointer;
background-image:linear-gradient(180deg,#f4f7ff 0%,#ffffff 100%);
border-radius:15px;
box-shadow:0px 0px 12px rgba(33, 73, 212, 0.06);
padding: 16px 20px;
transition: all 0.3s ease;
margin-bottom:15px;
&:last-child{
margin-bottom:0px;
}
a.font-14{
color: $primary-color;
}
&:hover{
&:hover, &.active{
background-image: url('./image/bkImg7.png');
background-size: 100% 100%;
div, a, p{
@ -954,7 +963,7 @@
background-size: 100% 100%;
}
.proTypeBox {
padding: 4px 15px;
padding: 4px 24px;
&.active {
color: $primary-color;
background-color: #ffffff;
@ -1035,6 +1044,87 @@
}
}
}
.top_detail{
background-image: url('./image/projectBk1.png');
background-size: 100% 100%;
flex: 0 0 calc(33.333% - 15px);
padding: 22px 20px 20px 20px;
border-radius:15px;
box-shadow:0px 0px 12px rgba(33, 73, 212, 0.1);
font-family: alibabaReg;
color: #091221;
.topitem{
background-color: rgba(76, 88, 118, 0.04);
padding: 4px 8px;
border-radius: 4px;
}
.topTitle{
font-family: alibaba;
font-size: 16px;
}
.pythonicon{
width: 14px;
height: 14px;
margin-right: 6px;
background-image: url('./image/python_color.png');
background-position: center;
background-size: 100% 100%;
}
&:hover{
cursor: pointer;
background-image: url('./image/projectBk4.png');
span, div{
color: white;
}
.color5d6:not(.task-hide-2){
opacity: 0.8;
}
.pd_tag_NSCC li{
color:#ffffff;
background-color:rgba(255, 255, 255, 0.12);
border: 1px solid rgba(255, 255, 255, 0.5);
}
.topitem{
background-color: rgba(255, 255, 255, 0.1);
}
.top_tag_NSCC{
li{
padding: 0 8px;
border-radius:4px;
margin-right: 8px;
color:#ffffff;
background-color:rgba(255, 255, 255, 0.12);
border: 1px solid rgba(255, 255, 255, 0.5);
}
}
.pythonicon{
width: 14px;
height: 14px;
margin-right: 6px;
background-image: url('./image/python_white.png');
background-position: center;
background-size: 100% 100%;
}
}
&.top:hover{
background-image: url('./image/projectBk4.png');
}
.top_tag_NSCC{
li{
padding: 0 8px;
border-radius:4px;
border: 1px solid transparent;
background:linear-gradient(281.55deg,rgba(10, 145, 255, 0.08) 1.48%,rgba(43, 103, 238, 0.08) 53.53%,rgba(133, 110, 250, 0.08) 95.62%);
margin-right: 8px;
}
}
}
.top_detailBox{
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
column-gap: 20px;
row-gap: 20px;
}
}
.source_1_bg_NSCC{
background-image: url('./image/bkImg9.png');
@ -1184,4 +1274,5 @@
}
}
}
}
}

View File

@ -97,11 +97,11 @@ function NewsCreate(props){
if(isEdit){
delete params.editorType;
return updateDoc(newsId, params).then(res=>{
const {data:{code, msg}} = res;
const {data:{code, msg , data}} = res;
setLoading(false);
if(code === 200){
message.success("提交成功");
history.push(`/zone/${deptId}/newdetail/${newsId}`);
history.push(`/zone/${deptId}/newdetail/${data}`);
}else{
message.error(msg || '提交失败,请联系管理员!')
}

View File

@ -34,16 +34,16 @@ function CategorySection({ category, index, zoneId, nsccTitle }) {
return projects.map((item, pIndex)=>{
return(
(!range || (range && pIndex >= range[0] && pIndex < range[1])) ? <div key={`${index}_${pIndex}`} className='cate-project-card'>
<div className='font-18 project-list-item-title mb20'>
{item.projectProperties && item.projectProperties.authorImageUrl && <img src={item.projectProperties.authorImageUrl} width={40} className='mr15'/>}
<a href={item.projectURL} className='font-bd'>{item.projectProperties && item.projectProperties.fromOwner}/{item.projectProperties && item.projectProperties.name && item.projectProperties.name.split("/").pop()}</a>
<div className='font-18 project-list-item-title mb12 df'>
{item.projectProperties && item.projectProperties.authorImageUrl && <img src={item.projectProperties.authorImageUrl} width={40} className='mr15' style={{borderRadius:"50%"}}/>}
<a href={item.projectURL} className='font-bd task-hide'>{item.projectProperties && item.projectProperties.fromOwner}/{item.projectProperties && item.projectProperties.name && item.projectProperties.name.split("/").pop()}</a>
{!showBtn && <i className='iconfont icon-jiantou21 font-16 ml10'></i>}
</div>
<div className="in_b_desc task-hide opacity8 font-15 mb15">
<div className="in_b_desc task-hide opacity8 font-15 mb10">
{item.projectProperties && item.projectProperties.description}
</div>
{item.projectProperties && item.projectProperties.topics && (
<ul className="project-list-item-tag mb20">
<ul className="project-list-item-tag mb15">
{item.projectProperties.topics.split(",").map((t, k) => (
<li key={k}>{t}</li>
))}

View File

@ -4,6 +4,7 @@ import { getProjectsTypeLists, getZoneStatistics, getProjectListByScore, getProj
import { projectCateConfig } from '../projectCateConfig';
import { getUniqueIdentifier, getUserName, getBrowserPlatform, getBrowserBrand } from '../../../utils';
import { setZoneVisits } from '../../../api';
import CountUp from 'react-countup';
import '../index.scss';
import './index.scss';
import Nodata from '../../../../Nodata';
@ -183,23 +184,31 @@ function ProjectCateList(props) {
))}
</div>
const countUpProps = {
redraw: false,
start: 0,
duration: 2,
// suffix: "+"
};
return (
<div className="project_cate_home project-cate-page">
<AddProjects needAudit={data && data.projectNeedAudit} id={id} visible={visible} typeList={typeList} onCancel={()=>setVisible(false)} role={role && role.role} onFresh={()=>{getTypeList();}}/>
{/* 数据统计部分 */}
<div className='project_cate_home_part1'>
{nsccTitle("数聚开源力量,实时见证开源生态的每一次进化", 0.1, "center pt80 fadeInChar")}
<div className='project-cate-1600'>
<div className="statistics-cards needScale">
{statsData.map((stat, index) => (
<div key={index} className="stat-card" style={{ animationDelay: `${0.3 + index * 0.1}s` }}>
<div className="stat-value font-20">
<span className='mr5'>{stat.value}</span>
{stat.suffix}
<div className='project-cate-1600 '>
<div className='statistics-cards-bc'>
<div className="statistics-cards needScale">
{statsData.map((stat, index) => (
<div key={index} className="stat-card" style={{ animationDelay: `${0.3 + index * 0.1}s` }}>
<div className="stat-value font-20">
<span className='mr5'><CountUp {...countUpProps} start={0} end={stat.value} /></span>
{stat.suffix}
</div>
<div className="font-15">{stat.label}</div>
</div>
<div className="font-15">{stat.label}</div>
</div>
))}
))}
</div>
</div>
{role && role.role !== "None" && <div className='center pt20 needFadeUp'>
{role.role === "Member" ? <GlowButton href={`/zone/NSCC/projects/self`} className="NSCC_project_btn blue_image font-15 mr50">我的项目<i className='iconfont icon-arrowRight font-16 ml5'></i></GlowButton>:""}

View File

@ -23,6 +23,7 @@
padding: 25px;
background-image: url('../../../img/project/cate_page_img2.png');
background-size: 100% 100%;
border-radius:15px;
&:hover {
.placeholder-img>img {
@ -152,7 +153,7 @@
flex: 0 0 calc(33.7% - 20px);
background-color: #ffffff;
border-radius:15px;
padding:40px;
padding:35px 40px;
&:hover{
background-image: url('../../../img/project/cate_page_card.png');
background-size: 101% 100%;
@ -176,8 +177,13 @@
background: url('../../../img/project/5_h_b.png') 98% 98% no-repeat;
color: #fff;
justify-content: flex-start;
padding:50px 80px 50px 45px;
padding:35px;
background-size: 100% 100%;
.project-list-item-tag{
li{
background-color: rgba(255,255,255,0.15);
}
}
.project-list-item-title{
a{
color: #fff;
@ -251,6 +257,7 @@
margin-bottom: 20px;
background-size: 100% 100%;
margin-right: 20px;
border-radius:15px;
.cateSixMainBox{
overflow: hidden;
}
@ -274,6 +281,7 @@
}
&:nth-child(2),&:nth-child(3){
width: calc(27.5% - 20px);
padding-bottom:54px;
}
}
}
@ -336,9 +344,15 @@
}
}
.statistics-cards-bc{
background-image: url(../../../img/vipTitleBc.png);
background-size: 100% 124%;
padding: 25px 0;
background-position-y: bottom;
}
.statistics-cards {
width: 80%;
margin: 25px auto;
margin: 0px auto;
display: grid;
justify-items: center;
grid-template-columns: repeat(4, 1fr);
@ -363,7 +377,7 @@
.cate_project_list_box .cate-project-card {
min-width: 0;
padding: 30px;
padding:26px;
border-radius: 15px;
display: flex;
flex-direction: column;
@ -377,7 +391,7 @@
}
.icon-jiantou21 {
color: inherit;
top: 0px;
top: 4px;
left: 0px;
opacity: 1;
transition: top 0.5s ease, left 0.5s ease, opacity 0.3s ease 0.1s;
@ -417,9 +431,9 @@
text-align: center;
height: 38px;
line-height: 38px;
margin-top: 35px;
margin-top: 30px;
background:linear-gradient(272.02deg,rgba(10, 145, 255, 0.12) 0.05%,rgba(43, 103, 238, 0.12) 55.23%,rgba(133, 110, 250, 0.12) 99.86%);
display:block;
&:hover {
background-color: #091221;
color: #fff;

View File

@ -0,0 +1,110 @@
import React , { useState , useEffect } from 'react';
import { Tag , Pagination } from 'antd';
import { getMemberAccountDetail, getPointsTransaction } from '../api';
import '../indexUser.scss';
export const memberStatusEnum = {
applying: '0',
isMember: '1',
notMember: '2'
}
const transactionTypeMap = {
add: { className: 'green', prefix: '+', valueKey: 'points', status: '已到账', statusClass: 'green' },
deduct: { className: 'red', prefix: '-', valueKey: 'points', status: '已支付', statusClass: 'blue' },
freezed: { className: 'orange', prefix: '-', valueKey: 'points', status: '冻结中', statusClass: 'orange' },
unfreezed: { className: 'green', prefix: '+', valueKey: 'points', status: '已退回', statusClass: 'gray' },
};
function getPointsShow(item) {
const config = transactionTypeMap[item.transactionType];
if (!config) {
return { className: '', pointsTxt: item.score, statusClass: '', status: '' };
}
const value = item[config.valueKey] || 0;
return {
className: config.className,
pointsTxt: `${config.prefix}${value}`,
status: config.status,
statusClass: config.statusClass
};
}
function scoreDetail(props){
const { id } = props;
const [ list , setList] = useState([]);
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(0);
const limit = 10;
useEffect(()=>{
if(id){
getDetail();
}
},[id, page])
function getDetail() {
getPointsTransaction(id, { pageNum: page, pageSize: limit }).then(res => {
if (res && res.data && res.data.code === 200) {
const processedRows = (res.data.rows || []).map(item => ({
...item,
pointsShow: getPointsShow(item)
}));
setList(processedRows)
setTotal(res.data.total || 0)
} else {
setList([])
setTotal(0)
}
}).catch(() => { setList([]); setTotal(0) })
}
return(
<div style={{width: '100%'}}>
<div className="detailBox">
<div className="detail">
<table className="detail_table">
<thead>
<tr>
<th width="240px">时间</th>
<th>积分明细</th>
<th width="200px" style={{textAlign: 'center'}}>分值变动</th>
<th width="240px" style={{textAlign: 'center'}}>状态</th>
<th>备注/回复</th>
</tr>
</thead>
<tbody>
{list.map((item, index) => (
<tr key={item.id}>
<td className="time">{item.createTime}</td>
<td className="desc">{item.subject}<br/><p>{item.subjectDesc}</p></td>
<td className={`score ${item.pointsShow?.className}`} style={{textAlign: 'center'}}>{item.pointsShow?.pointsTxt}</td>
<td style={{textAlign: 'center'}}>
<span className={`tag ${item.pointsShow?.statusClass}`}>{item.pointsShow?.status}</span>
</td>
<td className="remark">
{item.reason}
{
item.replyContent &&
<div className="reply">
<i className='iconfont icon-xiaoxi2 font-12 mr8'></i>
管理员{item.replyContent}
</div>
}
</td>
</tr>
))}
</tbody>
</table>
{ total > limit && (
<div style={{padding: '16px 0', textAlign: 'right'}}>
<Pagination showQuickJumper current={page} total={total} pageSize={limit} onChange={(p) => { setPage(p); window.scrollTo(0, 450) }} />
</div>
)}
</div>
</div>
</div>
)
}
export default scoreDetail;

View File

@ -0,0 +1,110 @@
import React , { useState , useEffect } from 'react';
import { Tag } from 'antd';
import '../indexUser.scss';
export const memberStatusEnum = {
applying: '0',
isMember: '1',
notMember: '2'
}
function ScoreRlue(props){
return(
<div style={{width: '100%'}}>
{/* className="font-bd font-30 mt70 mb40 align task-hide edu-txt-center" */}
<p className="rule_subject">超算专区<span className="font-bd font-30"> · </span>积分规则</p>
<div className="rule_box">
<div className="desc">
<h2>积分获取规则</h2>
<p>每日登录浏览互动等均可获得对应积分积分实时更新可在积分中心查看明细累计积分越多可解锁的福利与兑换权益越丰富轻松积累随心使用</p>
</div>
<div className="rules">
<table className="score-table">
<thead>
<tr>
<th width="320px">类别</th>
<th width="400px">行为项</th>
<th width="240px">奖励</th>
<th>限制说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span className="tag blue">准入</span>
</td>
<td className="action">入会审核通过</td>
<td className="score">+5</td>
<td className="remark">管理员审核通过后一次性发放</td>
</tr>
<tr>
<td><span className="tag green">活跃</span></td>
<td className="action">每日登录</td>
<td className="score">+1</td>
<td className="remark">每天首次加载专区页面触发上限1次/</td>
</tr>
<tr>
<td rowSpan={3}><span className="tag orange">内容</span></td>
<td className="action">发布文章</td>
<td className="score">+5</td>
<td className="remark">资讯审核通过后发放</td>
</tr>
<tr>
<td className="action">文章设为精选</td>
<td className="score">+5</td>
<td className="remark">管理员后台勾选精选标记时额外发放</td>
</tr>
<tr>
<td className="action">发布资源</td>
<td className="score">+5</td>
<td className="remark">资源附件审核通过后发放</td>
</tr>
<tr>
<td rowSpan={2}><span className="tag purple">影响力</span></td>
<td className="action">文章阅读量</td>
<td className="score">+2</td>
<td className="remark">每满 100 次阅读触发上限 50/每篇</td>
</tr>
<tr>
<td className="action">资源下载量</td>
<td className="score">+1</td>
<td className="remark">每下载 1 次触发上限 100/每个资源</td>
</tr>
<tr>
<td><span className="tag cyan">生态</span></td>
<td className="action">关联项目</td>
<td className="score">+10</td>
<td className="remark">个人项目成功关联至专区后发放</td>
</tr>
{/* <tr>
<td className="action">项目 Star</td>
<td className="score">+3</td>
<td className="remark">累计获得上限 60/每个项目</td>
</tr>
<tr>
<td className="action">项目 Fork</td>
<td className="score">+2</td>
<td className="remark">累计获得上限 40/每个项目</td>
</tr>
<tr>
<td><span className="tag brown">互动</span></td>
<td className="action">提交 Issue</td>
<td className="score">+5</td>
<td className="remark">提交有效 Issue 后发放上限 20/</td>
</tr>
<tr>
<td><span className="tag pink">贡献</span></td>
<td className="action">提交 PR</td>
<td className="score">+10</td>
<td className="remark">提交 PR 1 PR Merged 后奖 20 </td>
</tr> */}
</tbody>
</table>
</div>
</div>
</div>
)
}
export default ScoreRlue;

View File

@ -173,7 +173,8 @@ function SelfList(props){
const auditTypeEnom = {
create: '发布',
update: '编辑',
delete: '删除'
delete: '删除',
nonRepoUpdate: '编辑'
}
const statueName =(auditType)=>{

View File

@ -0,0 +1,119 @@
import React , { useState , useEffect } from 'react';
import { Spin } from 'antd';
import { getImageUrl } from 'educoder'
import { getVIPLists, getAuditStatus, applyJoin, getMemberStatus, getMemberInfo, getMemberPointsAccount, getMemberAccountDetail } from '../api';
import {getUniqueIdentifier,getBrowserPlatform,getBrowserBrand} from '../utils';
import { Link } from 'react-router-dom';
import FrozenImg from '../img/user/frozenScore.png';
import GainImg from '../img/user/gainScore.png';
import CostImg from '../img/user/costScore.png';
import ScoreDetail from './scoreDetail'
import '../indexUser.scss';
export const memberStatusEnum = {
applying: '0',
isMember: '1',
notMember: '2'
}
function ZoneScore(props){
const { deptId } = props.match.params;
const [ visible , setVisible ] = useState(false);
const [ awardVisible , setAwardVisible ] = useState(false);
const { id, showNotification, checkIfLogin, showLoginDialog, temp, sectionMemberTitle } = props;
const [ memberStatus , setMemberStatus] = useState(memberStatusEnum.notMember);
const [ accountInfo , setAccountInfo] = useState(null);
const [ loading , setLoading ] = useState(false);
useEffect(()=>{
let uuid = getUniqueIdentifier()
let url = props.location.pathname
let platform = getBrowserPlatform()
let browser = getBrowserBrand()
let remark = ` 操作系统:${platform};浏览器:${browser};`
},[])
useEffect(()=>{
if(id){
getMemberStatus();
}
},[id])
const infoItemsData = [{
img: FrozenImg,
title: '当前冻结积分',
scoreKey: 'frozenPoints'
}, {
img: GainImg,
title: '累计获取积分',
scoreKey: 'totalEarnedPoints'
}, {
img: CostImg,
title: '累计消费积分',
scoreKey: 'totalConsumedPoints'
}];
function getMemberStatus() {
setLoading(true);
getAuditStatus(id).then(res => {
if (res && res.data && res.data.code === 200) {
setMemberStatus(res.data.data)
} else {
setMemberStatus(memberStatusEnum.notMember)
}
if(res.data.data == memberStatusEnum.isMember) {
getInfo();
} else {
showNotification && showNotification('您当前不是专区会员,请先加入会员');
props.history && props.history.replace(`/zone/${deptId}/User`);
}
}).catch(() => { setMemberStatus(memberStatusEnum.notMember) })
.finally(() => {
setLoading(false)
});
}
function getInfo() {
getMemberPointsAccount(id).then(res => {
if (res && res.data && res.data.code === 200) {
setAccountInfo(res.data.data)
} else {
setAccountInfo(null)
}
}).catch(() => { setAccountInfo(null) })
}
return(
<div className={`boxmain width1600 ${temp}_Score_box`}>
<Spin spinning={loading}>
<div className="info">
<div className="info_title">
<Link className="title_a" to={`/zone/${deptId}/User`}>
<i className="iconfont icon-xiangzuojiantou font-20 mr18" style={{fontWeight: 600}}></i>
积分流水明细
</Link>
<p>每一笔积分变动清晰可查收支明细一目了然</p>
</div>
{infoItemsData.map((item, index) => (
<div key={index} className='items'>
<img src={item.img} alt=""/>
<div>
<h4>{item.title}</h4>
<p>{accountInfo ? accountInfo[item.scoreKey]?.toLocaleString() : '-'}</p>
</div>
</div>
))}
</div>
<ScoreDetail {...props} ></ScoreDetail>
</Spin>
</div>
)
}
export default ZoneScore;

View File

@ -0,0 +1,433 @@
import React , { useState , useEffect } from 'react';
import { Spin, Modal, Button } from 'antd';
import { getMainInfos, getAuditStatus, getMemberInfo, applyJoin, updateSelfInfo, setZoneVisits, getCurrentRole } from '../api';
import { Link } from 'react-router-dom';
import {getUniqueIdentifier,getUserName,getBrowserPlatform,getBrowserBrand} from '../utils';
import BannerSvg from '../img/user/banner.svg';
import JszdImg from '../img/user/jszd.png';
import HyslImg from '../img/user/hysl.png';
import RyxzImg from '../img/user/ryxz.png';
import ZdtgImg from '../img/user/zdtg.png';
import RyzsImg from '../img/user/ryzs.png';
import XwtjImg from '../img/user/xwtj.png';
import ZdtjImg from '../img/user/zdtj.png';
import XxcgImg from '../img/user/xxcg.png';
import ZjdyImg from '../img/user/zjdy.png';
import StarImg from '../img/user/star.png';
import SuccessImg from '../img/user/success.png';
import ScoreRlue from './scoreRule';
import UserEdit from '../Component/UserEdit';
import UserAward from '../Component/UserAward';
import MemberApply from '../Component/memberApply';
import PointsDoc from '../Component/pointsDoc';
import PointsProject from '../Component/pointsProject';
import ApplyAcitvity from '../Component/applyAcitvity';
import ApplyQA from '../Component/applyQA';
import '../indexUser.scss';
export const memberStatusEnum = {
applying: '0',
isMember: '1',
notMember: '2',
isAdmin: '3'
}
function ZoneUser(props){
const [ memberStatus , setMemberStatus] = useState(memberStatusEnum.notMember);
const [ memberInfo , setMemberInfo] = useState(null);
const [ zoneInfo , setZoneInfo] = useState(null);
const [ loading , setLoading ] = useState(false);
const { deptId } = props.match.params;
const [ visible , setVisible ] = useState(false);
const [ applyVisible , setApplyVisible ] = useState(false);
const [ awardVisible , setAwardVisible ] = useState(false);
const [ docVisible , setDocVisible ] = useState(false);
const [ projectVisible , setProjectVisible ] = useState(false);
const [ acitvityVisible , setAcitvityVisible ] = useState(false);
const [ qaVisible , setQaVisible ] = useState(false);
const [ successVisible , setSuccessVisible ] = useState(false);
const [ timeNum, setTimeNum] = useState(3);
const [ memberAccountInfo, setMemberAccountInfo ] = useState([]);
const [msg, setMsg] = useState('');
const { id, showNotification, checkIfLogin, showLoginDialog, temp, sectionMemberTitle } = props;
useEffect(()=>{
let uuid = getUniqueIdentifier()
let url = props.location.pathname
let platform = getBrowserPlatform()
let browser = getBrowserBrand()
let username = getUserName(props.current_user)
// if(!username) uuid = getUniqueIdentifier()
let remark = ` 操作系统:${platform};浏览器:${browser};`
setZoneVisits({url,username,uuid,remark})
},[])
useEffect(()=>{
if(id){
getMemberStatus();
getZoneInfo();
}
},[id])
useEffect(() => {
let temp = awardsInfoData.map(item => {
let tempData = Object.assign({}, item);
if(!memberInfo) return tempData;
if(item.key === 'certificate' && memberInfo.pointsEvent?.id) {
tempData.exist = true;
tempData.txt = '下载证书';
}
if(item.key === 'acitvity' && Array.isArray(memberInfo.applyList)) {
let index = memberInfo.applyList.findIndex(item => item.applyType === 'offlineActivityFreeze');
if(index !== -1) {
tempData.disabled = true;
tempData.txt = '待跟进';
}
}
if(item.key === 'qa' && Array.isArray(memberInfo.applyList)) {
let index = memberInfo.applyList.findIndex(item => item.applyType === 'expertQaFreeze');
if(index !== -1) {
tempData.disabled = true;
tempData.txt = '待跟进';
}
}
return tempData;
})
setMemberAccountInfo(temp);
}, [memberInfo])
useEffect(() => {
if (successVisible) {
const pid = setInterval(() => {
setTimeNum(prev => {
const newVal = prev - 1;
if (newVal <= 0) {
clearInterval(pid);
setSuccessVisible(false);
}
return newVal;
});
}, 1000);
return () => clearInterval(pid);
}
}, [successVisible]);
const infoItemsData = [{
img: JszdImg,
title: '专家技术指导',
desc: '超算顶尖专家一对一在线答疑及科研课题指导资格。'
}, {
img: HyslImg,
title: '行业沙龙优先权',
desc: '超算中心线下参观、沙龙及技术峰会名额优先预约。'
}, {
img: RyxzImg,
title: '贡献荣誉勋章',
desc: '社区电子荣誉证书,个人开源项目社区首页置顶推荐。'
}, {
img: ZdtgImg,
title: '内容与项目置顶推广',
desc: '文章、项目首页 7 天置顶推荐,提升曝光影响力。'
}];
const awardsInfoData= [{
key: 'certificate',
img: RyzsImg,
title: '专属电子荣誉证书',
desc: '贡献类证书,积分扣除自动生成',
score: 200,
unit: '张',
txt: '立即兑换'
},{
key: 'doc',
img: XwtjImg,
title: '专区首页新闻推荐',
desc: '将您的技术文章置顶至专区首页(7天)',
score: 500,
unit: '7天',
txt: '立即兑换'
},{
key: 'repo',
img: ZdtjImg,
title: '项目首页置顶推荐',
desc: '个人开源项目社区首页置顶推荐(7天)',
score: 800,
unit: '7天',
txt: '立即兑换'
},{
key: 'acitvity',
img: XxcgImg,
title: '线下参观/沙龙报名',
desc: '超算中心线下参观,沙龙优先报名权',
score: 1500,
unit: '次',
txt: '锁定资格'
},{
key: 'qa',
img: ZdtjImg,
title: '专家一对一答疑',
desc: '对接顶尖专家,解决核心技术难题',
score: 4000,
unit: '次',
txt: '立即预约'
}
];
function getMemberStatus() {
setLoading(true);
getCurrentRole(id).then(res => {
if (res && res.data && res.data.code === 200) {
if(res.data.data?.role === 'Member') {
setMemberStatus(memberStatusEnum.isMember)
getInfo();
} else if(res.data.data?.role === 'Manager') {
setMemberStatus(memberStatusEnum.isAdmin)
}
} else {
setMemberStatus(memberStatusEnum.notMember)
}
}).catch(() => { setMemberStatus(memberStatusEnum.notMember) })
.finally(() => {
setLoading(false)
});
// getAuditStatus(id).then(res => {
// if (res && res.data && res.data.code === 200) {
// setMemberStatus(res.data.data)
// } else {
// setMemberStatus(memberStatusEnum.notMember)
// }
// if(res.data.data == memberStatusEnum.isMember) {
// getInfo();
// }
// }).catch(() => { setMemberStatus(memberStatusEnum.notMember) })
// .finally(() => {
// console.log('api-over', memberStatus);
// setLoading(false)
// });
}
function getZoneInfo() {
getMainInfos(deptId).then(result=>{
if(result){
let data = result.data.data || {};
setZoneInfo(data);
}
})
}
function getInfo() {
getMemberInfo(id).then(res => {
if (res && res.data && res.data.code === 200) {
setMemberInfo(res.data.data)
} else {
setMemberInfo(null)
}
}).catch(() => { setMemberInfo(null) })
}
function onOk(e) {
applyJoin(id, e).then(res => {
if (res && res.data) {
showNotification(res.data.msg)
setApplyVisible(!applyVisible)
if (res.data.code === 200) {
setMemberStatus(memberStatusEnum.applying)
}
}
})
}
function onSure(e) {
updateSelfInfo(id, e).then(res => {
if (res && res.data) {
showNotification(res.data.msg)
setVisible(!visible)
if (res.data.code === 200) {
getInfo()
}
}
})
}
function apply() {
if(checkIfLogin()===false){
// showLoginDialog()
showLoginDialog(`/zone/${deptId}/user`)
return false;
}
setApplyVisible(!applyVisible)
}
function handleAwardSure(msg) {
showNotification(msg);
setAwardVisible(false);
getInfo();
}
function pointsCustom(item) {
if(item.disabled) return;
if(item.key == 'certificate') {
if(!item.exist) {
setAwardVisible(true);
} else {
let url = memberInfo.pointsEvent?.sourceData;
const link = document.createElement('a');
link.href = url;
link.click();
}
} else if(item.key == 'doc') {
setDocVisible(true);
} else if(item.key == 'repo') {
setProjectVisible(true);
} else if(item.key == 'acitvity') {
setAcitvityVisible(true);
} else if(item.key == 'qa') {
setQaVisible(true);
}
}
return(
<div className={`boxmain width1600 ${temp}_user_box`}>
<Spin spinning={loading}>
{memberStatus !== memberStatusEnum.isMember &&
<div className="banner_box">
<div className="info">
<div>
<p className="subject">加入 <label>智慧超算专区</label></p>
<p className="subject">解锁开发者专属贡献激励</p>
<a className='btn color-white' onClick={ apply }>
加入会员
<i className="iconfont icon-jiantou3 font-14 ml12"></i>
</a>
</div>
<div style={{flex: 1, textAlign: 'center'}}>
<div className="svgbox">
<div className="scan_line"></div>
<div className="corner corner-tl"></div>
<div className="corner corner-tr"></div>
<div className="corner corner-bl"></div>
<div className="corner corner-br"></div>
<img className='banner' src={BannerSvg} />
</div>
</div>
</div>
<div className="items">
{infoItemsData.map((item, index) => (
<div key={index} className='detail'>
<img src={item.img} alt=""/>
<h3>{item.title}</h3>
<p>{item.desc}</p>
</div>
))}
</div>
</div>
}
{memberStatus === memberStatusEnum.isMember && memberInfo != null &&
<div className="user_box">
<div className="info">
<img alt="头像" src={memberInfo.imageUrl} className="current_img"></img>
<div className="info_txt">
<h2 style={{height: '30px', lineHeight: '30px'}}>
<span onClick={() => {setVisible(true)}}>
{memberInfo.name}
<i className="iconfont icon-bianjipeizhi font-16 ml5"></i>
</span>
</h2>
<div style={{display: 'flex', alignItems: 'center', marginTop: '16px'}}>
<div className="level">
<img src={StarImg} style={{marginRight: '4px'}}></img>
{memberInfo.zoneMemberLevel?.name}
</div>
<p className="desc" style={{marginLeft: '12px'}} title={memberInfo.introduction}>{memberInfo.introduction}</p>
</div>
</div>
<div style={{height: '100%', display: 'flex', flexDirection: 'column'}}>
<h2 className="score">{memberInfo.zonePointsAccount?.availablePoints?.toLocaleString() || '0'}<label></label></h2>
<Link className="score_detail" to={`/zone/${deptId}/score`}>
积分明细
<i className="iconfont icon-xiangyoujiantou ml5" style={{fontSize: '10px !important'}}></i>
</Link>
</div>
</div>
<div className="awards">
{
memberAccountInfo.map((item, index) => (
<div className="award">
<h3><img src={item.img} alt="" style={{marginRight: 16}}/> {item.title}</h3>
<p>{item.desc}</p>
<div className="action">
<span><label>{item.score}积分</label>/{item.unit}</span>
{memberInfo?.zonePointsAccount?.availablePoints >= item.score ? (
<div className={`btn ${item.disabled ? 'disabled' : ''}`} onClick={() => pointsCustom(item)}>
{item.txt}
</div>
) : (
<div className="btn disabled">
积分不足
</div>
)}
</div>
</div>
))
}
</div>
</div>
}
</Spin>
<ScoreRlue {...props} />
<MemberApply visible={applyVisible} onOk={ onOk } onCancel={() => setApplyVisible(!applyVisible)} current_user={props.current_user}/>
<UserEdit visible={visible} member={memberInfo} zoneName={zoneInfo?.name} onSure={ onSure }
onCancel={()=>setVisible(false)}
/>
<UserAward visible={awardVisible} member={memberInfo} id={id} onSure={(msg) => handleAwardSure(msg)}
onCancel={()=>setAwardVisible(false)}
/>
<PointsDoc visible={docVisible} member={memberInfo}
onCancel={()=>setDocVisible(false)} onSure={() => { setDocVisible(false); setMsg('首页新闻推荐'); setSuccessVisible(true);getInfo();}}
/>
<PointsProject visible={projectVisible} member={memberInfo}
onCancel={()=>setProjectVisible(false)} onSure={() => { setProjectVisible(false); setMsg('首页项目推荐'); setSuccessVisible(true);getInfo();}}
/>
<ApplyAcitvity visible={acitvityVisible} member={memberInfo} zoneName={zoneInfo?.name}
onCancel={()=>setAcitvityVisible(false)} onSure={(msg) => { showNotification(msg); setAcitvityVisible(false); getInfo();}}
/>
<ApplyQA visible={qaVisible} member={memberInfo} zoneName={zoneInfo?.name}
onCancel={()=>setQaVisible(false)} onSure={(msg) => { showNotification(msg); setQaVisible(false); getInfo();}}
/>
<Modal
title=""
className="success_modal"
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={() => {setSuccessVisible(false)}}></i>}
visible={successVisible}
closable={true}
footer={null}
width={466}
>
<div className="info">
<img src={SuccessImg} alt=""/>
<p>恭喜获得专区<label>{msg}</label></p>
<Button className="btn_ok" onClick={() => {setSuccessVisible(false)}}>确定({timeNum}s)</Button>
</div>
</Modal>
</div>
)
}
export default ZoneUser;

View File

@ -218,6 +218,43 @@ export function getAuditStatus(id){
})
}
export function getMemberInfo(id){
return fetch({
url:`/zone/member/zone/${id}/memberInfo`,
method: 'get',
})
}
export function getMemberPointsAccount(id){
return fetch({
url:`/zone/points/account/overview/${id}`,
method: 'get',
})
}
export function getPointsAccountEvent(id){
return fetch({
url:`/zone/points/event/currentUser/${id}`,
method: 'get',
})
}
export function getPointsTransaction(id, params){
return fetch({
url:`/zone/points/transaction/currentUser/${id}`,
method: 'get',
params
})
}
export function getMemberAccountDetail(id, params){
return fetch({
url:`/zone/points/transaction/my/${id}`,
method: 'get',
params
})
}
/**会员申请状态 */
export function applyJoin(id,data) {
return fetch({
@ -227,6 +264,24 @@ export function applyJoin(id,data) {
});
}
// 更新会员信息
export function updateMemberInfo(id, data) {
return fetch({
url: `/zone/member/${ id }`,
method: 'PUT',
data: data
})
}
// 用户更新会员信息
export function updateSelfInfo(id, data) {
return fetch({
url: `/zone/member/customEdit/zone/${ id }`,
method: 'PUT',
data: data
})
}
// 资源模块
export function addResource(data) {
return fetch({
@ -498,6 +553,22 @@ export function getProjectListByScore(id,params) {
})
}
// 专区获取我的置顶文章
export function getMyTopArticle(id){
return fetch({
url:`/zone/points/account/article/top/${id}`,
method:"get",
})
}
// 专区获取我的置顶项目
export function getMyTopProject(id){
return fetch({
url:`/zone/points/account/project/top/${id}`,
method:"get",
})
}
// 获取已开通企业的组织列表
export function getOrzCompanyList(){
return fetch({
@ -584,4 +655,60 @@ export function deleteMemberProject(ids){
url: `/zone/zoneFront/removeProject/${ids}`,
method: 'delete',
})
}
}
export function applyAward(data) {
return fetch({
url: `/zone/points/account/certificate/redeem`,
method: 'post',
data
});
}
export function doApplyQA(data) {
return fetch({
url: `/zone/points/account/expert/qa/freeze`,
method: 'post',
data
});
}
export function doApplyActivity(data) {
return fetch({
url: `/zone/points/account/offlineActivity/freeze`,
method: 'post',
data
});
}
export function doDocTop(data) {
return fetch({
url: `/zone/points/account/article/top`,
method: 'post',
data
});
}
export function doProjectTop(data) {
return fetch({
url: `/zone/points/account/project/top`,
method: 'post',
data
});
}
// 获取文章列表
export function getPointsDocList(id){
return fetch({
url:`/zone/open/getTopDoc/${id}`,
method: 'get',
})
}
// 获取文章列表
export function getPointsProjectList(id){
return fetch({
url:`/zone/open/getTopProject/${id}`,
method: 'get',
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,262 @@
<svg style="position:absolute;inset:0;width:100%;height:100%;z-index:2;" viewBox="0 0 520 300" preserveAspectRatio="xMidYMid meet" fill="none"
xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="rackFront" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#2a4a80"/>
<stop offset="100%" stop-color="#1a3060"/>
</linearGradient>
<linearGradient id="rackTop" x1="0" y1="1" x2="1" y2="0">
<stop offset="0%" stop-color="#3a6aaa"/>
<stop offset="100%" stop-color="#4a80c0"/>
</linearGradient>
<linearGradient id="rackSide" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1a3060"/>
<stop offset="100%" stop-color="#0e1e40"/>
</linearGradient>
<linearGradient id="rackFront2" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#2e5090"/>
<stop offset="100%" stop-color="#1c3870"/>
</linearGradient>
<linearGradient id="rackTop2" x1="0" y1="1" x2="1" y2="0">
<stop offset="0%" stop-color="#4070b8"/>
<stop offset="100%" stop-color="#5088cc"/>
</linearGradient>
<linearGradient id="rackSide2" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1c3870"/>
<stop offset="100%" stop-color="#101e48"/>
</linearGradient>
<linearGradient id="rackFront3" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#284878"/>
<stop offset="100%" stop-color="#182e58"/>
</linearGradient>
<linearGradient id="rackTop3" x1="0" y1="1" x2="1" y2="0">
<stop offset="0%" stop-color="#3860a0"/>
<stop offset="100%" stop-color="#4878b8"/>
</linearGradient>
<linearGradient id="rackSide3" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#182e58"/>
<stop offset="100%" stop-color="#0c1838"/>
</linearGradient>
<linearGradient id="slotGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3060"/>
<stop offset="50%" stop-color="#2a4880"/>
<stop offset="100%" stop-color="#1e3060"/>
</linearGradient>
<linearGradient id="slotGrad2" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1a2850"/>
<stop offset="50%" stop-color="#3a5890"/>
<stop offset="100%" stop-color="#1a2850"/>
</linearGradient>
<linearGradient id="arcGrad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#60a5fa" stop-opacity="0.1"/>
<stop offset="50%" stop-color="#60a5fa" stop-opacity="0.8"/>
<stop offset="100%" stop-color="#60a5fa" stop-opacity="0.1"/>
</linearGradient>
<linearGradient id="arcGrad2" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#93c5fd" stop-opacity="0.1"/>
<stop offset="50%" stop-color="#93c5fd" stop-opacity="0.6"/>
<stop offset="100%" stop-color="#93c5fd" stop-opacity="0.1"/>
</linearGradient>
<radialGradient id="nodeGrad" cx="40%" cy="35%">
<stop offset="0%" stop-color="#60a5fa"/>
<stop offset="100%" stop-color="#2563eb"/>
</radialGradient>
<radialGradient id="nodeGrad2" cx="40%" cy="35%">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="100%" stop-color="#0284c7"/>
</radialGradient>
<radialGradient id="nodeGrad3" cx="40%" cy="35%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#4338ca"/>
</radialGradient>
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="2.5" result="blur"/>
<feMerge>
<feMergeNode in="blur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<filter id="softglow" x="-80%" y="-80%" width="260%" height="260%">
<feGaussianBlur stdDeviation="8" result="blur"/>
<feMerge>
<feMergeNode in="blur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<ellipse cx="260" cy="220" rx="200" ry="60" fill="rgba(74,128,255,0.06)"/>
<path d="M118 198 Q195 108 308 158" stroke="url(#arcGrad1)" stroke-width="1.5" fill="none" stroke-dasharray="6 4">
<animate attributeName="stroke-dashoffset" from="0" to="-40" dur="3s" repeatCount="indefinite"/>
</path>
<path d="M308 158 Q375 92 438 140" stroke="url(#arcGrad1)" stroke-width="1.5" fill="none" stroke-dasharray="6 4">
<animate attributeName="stroke-dashoffset" from="0" to="-40" dur="2.5s" repeatCount="indefinite"/>
</path>
<path d="M148 238 Q258 178 368 208" stroke="url(#arcGrad2)" stroke-width="1" fill="none" stroke-dasharray="4 5" opacity="0.55">
<animate attributeName="stroke-dashoffset" from="0" to="-36" dur="4s" repeatCount="indefinite"/>
</path>
<g transform="translate(55,55)">
<rect x="0" y="22" width="90" height="155" rx="4" fill="url(#rackFront)" opacity="0.92"/>
<path d="M0 22 L20 5 L110 5 L90 22 Z" fill="url(#rackTop)"/>
<path d="M90 22 L110 5 L110 177 L90 194 Z" fill="url(#rackSide)"/>
<rect x="8" y="32" width="74" height="15" rx="2" fill="url(#slotGrad)"/>
<rect x="8" y="53" width="74" height="15" rx="2" fill="url(#slotGrad)"/>
<rect x="8" y="74" width="74" height="15" rx="2" fill="url(#slotGrad2)"/>
<rect x="8" y="95" width="74" height="15" rx="2" fill="url(#slotGrad)"/>
<rect x="8" y="116" width="74" height="15" rx="2" fill="url(#slotGrad)"/>
<rect x="8" y="137" width="74" height="15" rx="2" fill="url(#slotGrad2)"/>
<rect x="8" y="158" width="74" height="11" rx="2" fill="url(#slotGrad)" opacity="0.7"/>
<circle cx="74" cy="39" r="3" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="1.8s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="60" r="3" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="2.2s" begin="0.3s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="81" r="3" fill="#facc15">
<animate attributeName="opacity" values="1;0.5;1" dur="0.8s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="102" r="3" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="2s" begin="0.6s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="123" r="3" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="1.6s" begin="0.9s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="144" r="3" fill="#60a5fa">
<animate attributeName="opacity" values="1;0.4;1" dur="3s" repeatCount="indefinite"/>
</circle>
<line x1="94" y1="32" x2="107" y2="19" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="53" x2="107" y2="40" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="74" x2="107" y2="61" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="95" x2="107" y2="82" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="116" x2="107" y2="103" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="137" x2="107" y2="124" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="158" x2="107" y2="145" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
</g>
<g transform="translate(215,22)">
<rect x="0" y="24" width="90" height="210" rx="4" fill="url(#rackFront2)" opacity="0.95"/>
<path d="M0 24 L20 6 L110 6 L90 24 Z" fill="url(#rackTop2)"/>
<path d="M90 24 L110 6 L110 234 L90 252 Z" fill="url(#rackSide2)"/>
<rect x="8" y="34" width="74" height="15" rx="2" fill="url(#slotGrad)"/>
<rect x="8" y="55" width="74" height="15" rx="2" fill="url(#slotGrad2)"/>
<rect x="8" y="76" width="74" height="15" rx="2" fill="url(#slotGrad)"/>
<rect x="8" y="97" width="74" height="15" rx="2" fill="url(#slotGrad)"/>
<rect x="8" y="118" width="74" height="15" rx="2" fill="url(#slotGrad2)"/>
<rect x="8" y="139" width="74" height="15" rx="2" fill="url(#slotGrad)"/>
<rect x="8" y="160" width="74" height="15" rx="2" fill="url(#slotGrad)"/>
<rect x="8" y="181" width="74" height="15" rx="2" fill="url(#slotGrad2)"/>
<rect x="8" y="202" width="74" height="12" rx="2" fill="url(#slotGrad)" opacity="0.7"/>
<circle cx="74" cy="41" r="3" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="1.4s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="62" r="3" fill="#f97316">
<animate attributeName="opacity" values="1;0.4;1" dur="0.7s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="83" r="3" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="2.3s" begin="0.4s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="104" r="3" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="1.9s" begin="0.7s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="125" r="3" fill="#facc15">
<animate attributeName="opacity" values="1;0.5;1" dur="1.1s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="146" r="3" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="1.6s" begin="0.3s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="167" r="3" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="2.1s" begin="0.8s" repeatCount="indefinite"/>
</circle>
<circle cx="74" cy="188" r="3" fill="#60a5fa">
<animate attributeName="opacity" values="1;0.4;1" dur="2.8s" repeatCount="indefinite"/>
</circle>
<line x1="94" y1="34" x2="107" y2="20" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="55" x2="107" y2="41" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="76" x2="107" y2="62" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="97" x2="107" y2="83" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="118" x2="107" y2="104" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="139" x2="107" y2="125" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="160" x2="107" y2="146" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="181" x2="107" y2="167" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
<line x1="94" y1="202" x2="107" y2="188" stroke="#6080b0" stroke-width="0.6" opacity="0.5"/>
</g>
<g transform="translate(382,72)">
<rect x="0" y="20" width="72" height="130" rx="4" fill="url(#rackFront3)" opacity="0.9"/>
<path d="M0 20 L16 5 L88 5 L72 20 Z" fill="url(#rackTop3)"/>
<path d="M72 20 L88 5 L88 150 L72 165 Z" fill="url(#rackSide3)"/>
<rect x="6" y="29" width="60" height="13" rx="2" fill="url(#slotGrad)"/>
<rect x="6" y="48" width="60" height="13" rx="2" fill="url(#slotGrad2)"/>
<rect x="6" y="67" width="60" height="13" rx="2" fill="url(#slotGrad)"/>
<rect x="6" y="86" width="60" height="13" rx="2" fill="url(#slotGrad)"/>
<rect x="6" y="105" width="60" height="13" rx="2" fill="url(#slotGrad2)"/>
<rect x="6" y="124" width="60" height="10" rx="2" fill="url(#slotGrad)" opacity="0.7"/>
<circle cx="60" cy="35" r="2.5" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="2s" repeatCount="indefinite"/>
</circle>
<circle cx="60" cy="54" r="2.5" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="1.6s" begin="0.5s" repeatCount="indefinite"/>
</circle>
<circle cx="60" cy="73" r="2.5" fill="#facc15">
<animate attributeName="opacity" values="1;0.5;1" dur="0.9s" repeatCount="indefinite"/>
</circle>
<circle cx="60" cy="92" r="2.5" fill="#4ade80">
<animate attributeName="opacity" values="1;0.3;1" dur="1.8s" begin="0.2s" repeatCount="indefinite"/>
</circle>
<circle cx="60" cy="111" r="2.5" fill="#60a5fa">
<animate attributeName="opacity" values="1;0.4;1" dur="3.2s" repeatCount="indefinite"/>
</circle>
</g>
<g transform="translate(118,198)">
<circle r="22" fill="url(#nodeGrad)" opacity="0.85" filter="url(#softglow)">
<animate attributeName="r" values="22;24;22" dur="3s" repeatCount="indefinite"/>
</circle>
<circle r="22" fill="none" stroke="#4a8fff" stroke-width="1.2" opacity="0.5">
<animate attributeName="r" values="22;34;22" dur="3s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="0.5;0;0.5" dur="3s" repeatCount="indefinite"/>
</circle>
<line x1="-9" y1="0" x2="9" y2="0" stroke="white" stroke-width="1.8" opacity="0.85"/>
<line x1="0" y1="-9" x2="0" y2="9" stroke="white" stroke-width="1.8" opacity="0.85"/>
</g>
<g transform="translate(308,158)">
<circle r="17" fill="url(#nodeGrad2)" opacity="0.85" filter="url(#softglow)">
<animate attributeName="r" values="17;19;17" dur="2.5s" begin="0.5s" repeatCount="indefinite"/>
</circle>
<circle r="17" fill="none" stroke="#60a5fa" stroke-width="1" opacity="0.4">
<animate attributeName="r" values="17;28;17" dur="2.5s" begin="0.5s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="0.4;0;0.4" dur="2.5s" begin="0.5s" repeatCount="indefinite"/>
</circle>
<path d="M0 -7 L6 -3.5 L6 3.5 L0 7 L-6 3.5 L-6 -3.5 Z" stroke="white" stroke-width="1.3" fill="none" opacity="0.9"/>
</g>
<g transform="translate(438,140)">
<circle r="19" fill="url(#nodeGrad3)" opacity="0.8" filter="url(#softglow)">
<animate attributeName="r" values="19;21;19" dur="3.5s" begin="1s" repeatCount="indefinite"/>
</circle>
<circle r="19" fill="none" stroke="#93c5fd" stroke-width="1" opacity="0.4">
<animate attributeName="r" values="19;30;19" dur="3.5s" begin="1s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="0.4;0;0.4" dur="3.5s" begin="1s" repeatCount="indefinite"/>
</circle>
<path d="M-6 3 Q0 -5 6 3" stroke="white" stroke-width="1.4" fill="none" opacity="0.85"/>
<path d="M-10 7 Q0 -10 10 7" stroke="white" stroke-width="1.1" fill="none" opacity="0.5"/>
</g>
<circle r="5" fill="#7dd3fc" filter="url(#glow)">
<animateMotion dur="3s" repeatCount="indefinite" path="M118 198 Q195 108 308 158"/>
<animate attributeName="opacity" values="0;1;1;0" dur="3s" repeatCount="indefinite"/>
</circle>
<circle r="4" fill="#a5f3fc" filter="url(#glow)">
<animateMotion dur="2.5s" begin="0.8s" repeatCount="indefinite" path="M308 158 Q375 92 438 140"/>
<animate attributeName="opacity" values="0;1;1;0" dur="2.5s" begin="0.8s" repeatCount="indefinite"/>
</circle>
<circle r="3.5" fill="#bfdbfe" filter="url(#glow)">
<animateMotion dur="4s" begin="1.5s" repeatCount="indefinite" path="M148 238 Q258 178 368 208"/>
<animate attributeName="opacity" values="0;0.8;0.8;0" dur="4s" begin="1.5s" repeatCount="indefinite"/>
</circle>
<circle r="3.5" fill="#c7d2fe" filter="url(#glow)">
<animateMotion dur="3.2s" begin="2s" repeatCount="indefinite" path="M438 140 Q375 92 308 158"/>
<animate attributeName="opacity" values="0;0.7;0.7;0" dur="3.2s" begin="2s" repeatCount="indefinite"/>
</circle>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB

View File

@ -36,6 +36,14 @@ const VIP = Loadable({
loader: () => import("./Pages/zoneVIP"),
loading: Loading,
});
const User = Loadable({
loader: () => import("./Pages/zoneUser"),
loading: Loading,
});
const Score = Loadable({
loader: () => import("./Pages/zoneScore"),
loading: Loading,
});
const Apply = Loadable({
loader: () => import("./Pages/apply"),
loading: Loading,
@ -141,6 +149,7 @@ const DataSetList = Loadable({
function Index(props){
const [ data , setData ] = useState(undefined);
const [ adminUrl , setAdminUrl ] = useState(undefined);
const [ adminLoaded, setAdminLoaded ] = useState(false);
const { deptId } = props.match.params;
const [ id , setId ] = useState(undefined);
const [ temp , setTemp ] = useState(tempEnum.zone);
@ -204,7 +213,7 @@ function Index(props){
}else{
setAdminUrl(undefined);
}
}).catch(error=>{})
}).catch(error=>{}).finally(() => setAdminLoaded(true))
}
function getRole(id){
@ -218,7 +227,7 @@ function Index(props){
return(
<div className="information_main">
{ (!isSearch && !projectCateDetail && !isSourcedetail && deptId!=="apply") && (id ? <PublicBanner {...props} data={data} temp={ temp } adminUrl={adminUrl} id={id}/> : <div style={{ width: '100%', height: '450px' }}></div>)}
{ (!isSearch && !projectCateDetail && !isSourcedetail && deptId!=="apply") && (id && adminLoaded ? <PublicBanner {...props} data={data} temp={ temp } adminUrl={adminUrl} id={id}/> : <div style={{ width: '100%', height: '450px' }}></div>)}
<Switch>
<Route
path="/zone/:deptId/news/self"
@ -316,6 +325,22 @@ function Index(props){
<VIP {...props} {...p} id={id} temp={ temp } sectionMemberTitle={data && data.sectionMemberTitle}/>
)}
></Route>
{(adminLoaded && !adminUrl && data && data.sectionPointsShow) && (
<Route
path="/zone/:deptId/user"
render={(p) => (
<User {...props} {...p} id={id} temp={ temp } sectionUserTitle={data && data.sectionUserTitle}/>
)}
></Route>
)}
{(adminLoaded && !adminUrl && data && data.sectionPointsShow) && (
<Route
path="/zone/:deptId/score"
render={(p) => (
<Score {...props} {...p} id={id} temp={ temp } sectionScoreTitle={data && data.sectionScoreTitle}/>
)}
></Route>
)}
<Route
path="/zone/:deptId/projects/self"
render={(p) => (

View File

@ -2183,6 +2183,149 @@
}
}
}
.totalMemeber{
font-family:Alibaba PuHuiTi;
font-weight:500;
color:#091221;
font-size:18px;
padding:30px 40px;
display: flex;
align-items: center;
line-height:25px;
span{
padding:0 6px;
height:21px;
line-height:21px;
background:#f1ebff;
border-radius:4px;
margin-left:12px;
color:#7a45ec;
font-size:12px;
}
}
.zoneMemberRow {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-items: flex-start;
padding:0 25px 30px;
}
.memeberSlider{
position: relative;
.custom-prev-arrow,.custom-next-arrow{
position:absolute;
right:45px;
top:-55px;
left:unset;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
cursor:pointer;
i{
font-size:30px!important;
}
&.arrow-disabled{
i{
opacity: 0.4;
}
cursor: not-allowed;
}
}
.custom-prev-arrow{
right:95px;
}
}
.zoneMemberItem{
padding-top:45px;
width:163px;
margin:15px;
position: relative;
&:hover{
.zoneMI_box .zoneMI_img{
a::before{
animation: buttonBorderSpin 3s linear infinite forwards;
}
}
.zoneMI_box .zoneMI_name{
color:#466aff;
}
}
&::before,&::after{
content:"";
position: absolute;
height: 117px;
left:-1px;
right: -1px;
bottom: -1px;
z-index:0;
border-radius:8px;
background:linear-gradient(180deg,rgba(219, 70, 255, 0.17) 0%,rgba(111, 85, 255, 0.17) 42.36%,rgba(70, 106, 255, 0.17) 100%);
}
&::after{
height: 115px;
z-index: 1;
left:0;
right:0;
bottom:0;
background: #fff;
}
.zoneMI_box{
height: 115px;
padding-bottom: 10px;
border-radius:8px;
display: flex;
flex-direction: column;
justify-content: flex-end;
position: relative;
align-items: center;
position: relative;
z-index: 10;
background:linear-gradient(313.05deg,#ffffff 19.33%,rgba(242, 246, 255, 0.08) 62.79%,rgba(133, 110, 250, 0.08) 97.93%);
.zoneMI_img{
position: absolute;
left:50%;
margin-left:-40px;
top:-40px;
z-index:1000;
a{
position: relative;
&::before{
content:"";
position: absolute;
height: 84px;
width:84px;
left:-2px;
right: -2px;
bottom: -2px;
top: -2px;
z-index:0;
border-radius:50%;
background:linear-gradient(168.49deg,#466aff -0.45%,#e2e7ff 22.8%,#f3c9ff 42.17%,#ffffff 71.05%);
}
}
img{
border-radius:50%;
position: relative;
z-index:2;
background: #fff;
}
}
.zoneMI_name{
color:#091221;
font-size:18px;
font-family:alibaba;
height:25px;
line-height:25px;
width: 100%;
text-align: center;
padding: 0 10px;
}
}
}
.NSCC_source_box{
background-image: url('./img/source-bg.png');
background-size: 100% 100%;
@ -2388,4 +2531,9 @@
opacity: 1;
transform: translateY(0px);
}
}
@keyframes buttonBorderSpin {
100% {
transform: rotate(360deg);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,239 @@
.zone_user_container {
display: flex;
flex-direction: column;
min-height: 100vh;
background: #f5f5f5;
/* 顶部导航栏 */
.user_header {
background: #1890ff;
height: 60px;
display: flex;
align-items: center;
padding: 0 20px;
.header_content {
width: 100%;
max-width: 1200px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
.logo_area {
display: flex;
align-items: center;
.logo_icon {
width: 40px;
height: 40px;
background: #fff;
border-radius: 8px;
margin-right: 12px;
}
.logo_text {
display: flex;
flex-direction: column;
.logo_title {
color: #fff;
font-size: 18px;
font-weight: 600;
line-height: 1.2;
}
.logo_url {
color: rgba(255, 255, 255, 0.8);
font-size: 12px;
line-height: 1.2;
}
}
}
.header_nav {
display: flex;
align-items: center;
gap: 24px;
.nav_item {
color: #fff;
font-size: 14px;
text-decoration: none;
opacity: 0.9;
&:hover {
opacity: 1;
}
}
.nav_avatar {
width: 32px;
height: 32px;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
}
}
}
}
/* 登录卡片 */
.login_card {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 20px;
.login_card_header {
width: 364px;
margin-bottom: 20px;
position: relative;
.login_title {
font-size: 24px;
font-weight: 600;
color: #333;
margin: 0;
}
.login_decorate {
position: absolute;
top: 0;
right: 0;
width: 60px;
height: 60px;
background: linear-gradient(135deg, #1890ff 0%, #40a9ff 100%);
border-radius: 50%;
opacity: 0.1;
}
}
.login_tabs {
width: 364px;
background: #fff;
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
.ant-tabs-nav {
width: 100%;
margin-bottom: 20px;
.ant-tabs-tab {
width: 50%;
text-align: center;
font-size: 15px;
padding: 10px 0;
margin: 0;
}
}
}
.login_form {
.login_input {
height: 44px;
border-radius: 6px;
font-size: 14px;
.ant-input-prefix {
color: #999;
margin-right: 8px;
}
}
.login_options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
.forgot_password {
color: #1890ff;
font-size: 14px;
&:hover {
color: #40a9ff;
}
}
}
.login_button {
height: 44px;
border-radius: 6px;
font-size: 16px;
font-weight: 500;
background: #1890ff;
border-color: #1890ff;
&:hover,
&:focus {
background: #40a9ff;
border-color: #40a9ff;
}
}
}
.code_input_wrapper {
display: flex;
gap: 12px;
.code_input {
flex: 1;
}
.code_button {
width: 110px;
height: 44px;
border-radius: 6px;
white-space: nowrap;
}
}
.login_footer {
width: 364px;
text-align: center;
padding: 20px 24px;
background: #fff;
border-radius: 0 0 12px 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
margin-top: -24px;
border-top: 1px solid #f0f0f0;
font-size: 14px;
color: #666;
.register_link {
color: #1890ff;
font-weight: 500;
&:hover {
color: #40a9ff;
}
}
}
}
/* 底部联系栏 */
.user_footer {
background: #1890ff;
padding: 20px;
text-align: center;
.footer_content {
display: flex;
flex-direction: column;
gap: 8px;
.contact {
color: #fff;
font-size: 14px;
}
.copyright {
color: rgba(255, 255, 255, 0.8);
font-size: 12px;
}
}
}
}