添加框架内容

This commit is contained in:
linxd
2025-06-16 16:22:26 +08:00
parent 1eabd737a6
commit c7b9ffac10
37 changed files with 2328 additions and 41 deletions

View File

@ -1,11 +1,13 @@
import { defineConfig } from 'umi';
import defaultSettings from './defaultSettings';
import defaultSettings,{antdTheme} from './defaultSettings';
// import proxy from './proxy';
import PageRoutes from './router.config'
const { REACT_APP_ENV } = process.env;
export default defineConfig({
hash: true,
antd: {},
antd: {
},
dva: {
hmr: true,
},
@ -30,6 +32,8 @@ export default defineConfig({
'primary-color': defaultSettings.primaryColor,
'heading-color': defaultSettings.headingColor,
'text-color': defaultSettings.textColor,
// 更改antd 组件颜色
...antdTheme
},
// @ts-ignore
title: false,

View File

@ -2,15 +2,15 @@ import { Settings as ProSettings } from '@ant-design/pro-layout';
type DefaultSettings = ProSettings & {
pwa: boolean;
headingColor:string;
textColor:string;
headingColor: string;
textColor: string;
};
const proSettings: DefaultSettings = {
navTheme: 'light',
primaryColor: 'rgb(0,79,142)',
headingColor:"#000",
textColor:"#000",
headingColor: "#000",
textColor: "#000",
layout: 'side',
contentWidth: 'Fluid',
fixedHeader: false,
@ -24,6 +24,15 @@ const proSettings: DefaultSettings = {
iconfontUrl: '',
};
export const antdTheme = {
// 更改antd 组件颜色
'table-header-bg': 'rgb(241,245,251)',
'table-row-hover-bg': 'rgb(241,245,251)',
'table-padding-vertical': '12px',
'table-header-color': 'rgb(143,146,153)'
}
export type { DefaultSettings };
export default proSettings;

View File

@ -1,5 +1,21 @@
export default [
{
path: '/login',
component: '@/pages/login/login',
},
{
path: '/register',
routes: [
{
path: '/register/supplier',
component: '@/pages/register/supplier',
},
{
path: '/register/expert',
component: '@/pages/register/expert',
}
]
},
{
path: '/',
component: '@/layouts/Index',
@ -18,6 +34,11 @@ export default [
path: '/announce',
component: '@/pages/announce/announce',
},
{
name: 'announceInfo',
path: '/announce/announceInfo',
component: '@/pages/announce/announceInfo',
},
{
name: 'policy',
path: '/policy',
@ -28,6 +49,12 @@ export default [
path: '/notice',
component: '@/pages/notice/notice',
},
{
name: 'noticeInfo',
path: '/notice/noticeInfo',
component: '@/pages/notice/noticeInfo',
activeMenu: 'notice'
},
{
name: 'download',
path: '/download',

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,258 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=4950533" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe60c;</span>
<div class="name">地址</div>
<div class="code-name">&amp;#xe60c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe603;</span>
<div class="name">电话</div>
<div class="code-name">&amp;#xe603;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe645;</span>
<div class="name">邮箱</div>
<div class="code-name">&amp;#xe645;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1750055522436') format('woff2'),
url('iconfont.woff?t=1750055522436') format('woff'),
url('iconfont.ttf?t=1750055522436') format('truetype'),
url('iconfont.svg?t=1750055522436#iconfont') format('svg');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-dizhi"></span>
<div class="name">
地址
</div>
<div class="code-name">.icon-dizhi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-dianhua"></span>
<div class="name">
电话
</div>
<div class="code-name">.icon-dianhua
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-youxiang"></span>
<div class="name">
邮箱
</div>
<div class="code-name">.icon-youxiang
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-dizhi"></use>
</svg>
<div class="name">地址</div>
<div class="code-name">#icon-dizhi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-dianhua"></use>
</svg>
<div class="name">电话</div>
<div class="code-name">#icon-dianhua</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-youxiang"></use>
</svg>
<div class="name">邮箱</div>
<div class="code-name">#icon-youxiang</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

View File

@ -0,0 +1,28 @@
@font-face {
font-family: "iconfont"; /* Project id 4950533 */
src: url('iconfont.woff2?t=1750055522436') format('woff2'),
url('iconfont.woff?t=1750055522436') format('woff'),
url('iconfont.ttf?t=1750055522436') format('truetype'),
url('iconfont.svg?t=1750055522436#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-dizhi:before {
content: "\e60c";
}
.icon-dianhua:before {
content: "\e603";
}
.icon-youxiang:before {
content: "\e645";
}

View File

@ -0,0 +1 @@
window._iconfont_svg_string_4950533='<svg><symbol id="icon-dizhi" viewBox="0 0 1024 1024"><path d="M512.768 1024H512a65.536 65.536 0 0 1-47.283-20.224c-9.677-10.112-97.434-102.656-184.73-219.904C162.15 625.664 102.4 499.456 102.4 408.909 102.4 183.424 286.157 0 512 0s409.6 183.424 409.6 408.883c0 54.784-21.12 121.907-62.746 199.45-40.166 74.777-100.556 161.638-179.532 258.201l-0.64 0.768-117.53 134.4A64.589 64.589 0 0 1 512.768 1024zM512 600.294c105.728 0 191.744-85.862 191.744-191.41S617.728 217.471 512 217.471s-191.744 85.862-191.744 191.411S406.272 600.294 512 600.294z" fill="#323232" ></path></symbol><symbol id="icon-dianhua" viewBox="0 0 1024 1024"><path d="M616.3 664.3l-39.2 28.8s-39.3 18.3-86.3-23.5c-47.1-41.9-130.7-137.5-154.2-192.3-23.5-54.9 23.5-78.4 23.5-78.4s61.5-51 64-60.1c2.6-9.2 36.6-45.7-36.6-143.8-73.2-98-90.2-78.4-129.4-48.4-39.2 30-94.2 88.9-105.9 156.9-11.8 68-19.6 151.6 79.8 300.7S481.7 867 565.3 885.3c83.8 18.3 142.6 30 226.1-37.9 83.7-68 98.2-74.5 60.2-122.9-37.9-48.4-121.3-106.4-133.8-108.8-12.4-2.5-30.4-6.7-58.5 14.2-28.2 20.8-43 34.4-43 34.4" ></path></symbol><symbol id="icon-youxiang" viewBox="0 0 1024 1024"><path d="M886.3 299.8l-381.1 220-371.6-214.6c3.6-56.2 50.3-100.7 107.4-100.7h538.3c55.3 0 100.9 41.6 107 95.3z m0.7 78.8v334.9c0 59.5-48.2 107.7-107.7 107.7H241c-59.5 0-107.7-48.2-107.7-107.7V384.3l354.9 204.9c12.2 7 26.9 5.7 37.5-2.1 0.5-0.2 0.9-0.5 1.4-0.8L887 378.6z" ></path></symbol></svg>',(n=>{var t=(e=(e=document.getElementsByTagName("script"))[e.length-1]).getAttribute("data-injectcss"),e=e.getAttribute("data-disable-injectsvg");if(!e){var i,o,c,d,s,a=function(t,e){e.parentNode.insertBefore(t,e)};if(t&&!n.__iconfont__svg__cssinject__){n.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(t){console&&console.log(t)}}i=function(){var t,e=document.createElement("div");e.innerHTML=n._iconfont_svg_string_4950533,(e=e.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",e=e,(t=document.body).firstChild?a(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(i,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),i()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(c=i,d=n.document,s=!1,r(),d.onreadystatechange=function(){"complete"==d.readyState&&(d.onreadystatechange=null,l())})}function l(){s||(s=!0,c())}function r(){try{d.documentElement.doScroll("left")}catch(t){return void setTimeout(r,50)}l()}})(window);

View File

@ -0,0 +1,30 @@
{
"id": "4950533",
"name": "中远",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "5093357",
"name": "地址",
"font_class": "dizhi",
"unicode": "e60c",
"unicode_decimal": 58892
},
{
"icon_id": "6682217",
"name": "电话",
"font_class": "dianhua",
"unicode": "e603",
"unicode_decimal": 58883
},
{
"icon_id": "7140587",
"name": "邮箱",
"font_class": "youxiang",
"unicode": "e645",
"unicode_decimal": 58949
}
]
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Created by iconfont</metadata>
<defs>
<font id="iconfont" horiz-adv-x="1024">
<font-face
font-family="iconfont"
font-weight="400"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="dizhi" unicode="&#58892;" d="M512.768-128H512a65.536 65.536 0 0 0-47.283 20.224c-9.677 10.112-97.434 102.656-184.73 219.904C162.15 270.336 102.4 396.544 102.4 487.091 102.4 712.576 286.157 896 512 896s409.6-183.424 409.6-408.883c0-54.784-21.12-121.907-62.746-199.45-40.166-74.777-100.556-161.638-179.532-258.201l-0.64-0.768-117.53-134.4A64.589 64.589 0 0 0 512.768-128zM512 295.706c105.728 0 191.744 85.862 191.744 191.41S617.728 678.529 512 678.529s-191.744-85.862-191.744-191.411S406.272 295.706 512 295.706z" horiz-adv-x="1024" />
<glyph glyph-name="dianhua" unicode="&#58883;" d="M616.3 231.7l-39.2-28.8s-39.3-18.3-86.3 23.5c-47.1 41.9-130.7 137.5-154.2 192.3-23.5 54.9 23.5 78.4 23.5 78.4s61.5 51 64 60.1c2.6 9.2 36.6 45.7-36.6 143.8-73.2 98-90.2 78.4-129.4 48.4-39.2-30-94.2-88.9-105.9-156.9-11.8-68-19.6-151.6 79.8-300.7S481.7 29 565.3 10.7c83.8-18.3 142.6-30 226.1 37.9 83.7 68 98.2 74.5 60.2 122.9-37.9 48.4-121.3 106.4-133.8 108.8-12.4 2.5-30.4 6.7-58.5-14.2-28.2-20.8-43-34.4-43-34.4" horiz-adv-x="1024" />
<glyph glyph-name="youxiang" unicode="&#58949;" d="M886.3 596.2l-381.1-220-371.6 214.6c3.6 56.2 50.3 100.7 107.4 100.7h538.3c55.3 0 100.9-41.6 107-95.3z m0.7-78.8v-334.9c0-59.5-48.2-107.7-107.7-107.7H241c-59.5 0-107.7 48.2-107.7 107.7V511.7l354.9-204.9c12.2-7 26.9-5.7 37.5 2.1 0.5 0.2 0.9 0.5 1.4 0.8L887 517.4z" horiz-adv-x="1024" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/assets/img/loginBg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

View File

@ -1,6 +1,8 @@
//定义主题颜色
@main-color: rgb(0, 79, 142);
@main-text-color: #000;
@main-text-color-1: #333;
@main-text-color-2: #666;
@main-danger-color: rgb(214, 0, 14);
//灰色

View File

@ -0,0 +1,18 @@
import { createFromIconfontCN } from '@ant-design/icons';
import React from 'react';
interface IconFontProps {
type: string;
[key: string]: any;
}
const IconFont: React.FC<IconFontProps> = (props) => {
const Icon = createFromIconfontCN({
// 线上
// scriptUrl: '//at.alicdn.com/t/c/font_4950533_qp1wyf22tmb.js',
// 本地
scriptUrl: require('@/assets/iconfont/iconfont.js'),
});
return <Icon {...props} />;
};
export default IconFont;

View File

@ -0,0 +1,7 @@
@import '../../baseStyle.less';
.spaceBlock {
height: 10px;
margin: 0 -15px;
margin-top: 20px;
background: rgba(@gray, 0.3);
}

View File

@ -0,0 +1,7 @@
import React from 'react';
import './SpaceBlock.less';
const SpaceBlock: React.FC = () => {
return <div className="spaceBlock" />;
};
export default SpaceBlock;

View File

@ -6,7 +6,19 @@ body,
#root {
height: 100%;
}
.layout-content {
box-sizing: border-box;
height: calc(100% - 60px);
overflow: auto;
padding: 15px 0;
background: rgba(@gray, 0.3);
.layout-content-main {
width: @width;
margin: 0 auto;
background: #fff;
padding: 15px;
}
}
.colorWeak {
filter: invert(80%);
}

View File

@ -1,9 +1,27 @@
@import '../baseStyle.less';
.header {
position: relative;
z-index: 1;
display: flex;
align-items: flex-end;
align-items: center;
justify-content: space-between;
width: @width;
margin: 0 auto;
.logo {
height: 45px;
}
}
.header-menu {
display: flex;
flex: 1;
align-items: center;
justify-content: flex-end;
.ant-menu-horizontal {
line-height: 58px;
border: none;
}
}
.user {
margin-left: 15px;
}

View File

@ -8,7 +8,7 @@ import HeaderMenu from './HeaderMenu';
const Header: React.FC = (props) => {
return (
<div className="header">
<img src={LogoImg} alt="logo" />
<img className='logo' src={LogoImg} alt="logo" />
<HeaderMenu />
</div>
);

View File

@ -1,7 +0,0 @@
.header-menu{
display: flex;
align-items: center;
.ant-menu-horizontal{
border: none;
}
}

View File

@ -2,13 +2,13 @@ import React, { useEffect, useState } from 'react';
import { Menu } from 'antd';
import Language from './Language';
import { useIntl, Link, useHistory } from 'umi';
import User from './User';
interface IMenuItem {
label: string;
key: string;
path: string;
}
// 引入样式文件 useIntl().formatMessage({ id: 'menu.首页' }),
import './HeaderMenu.less';
const items: IMenuItem[] = [
{
label: 'menu.首页',
@ -53,6 +53,10 @@ const HeaderMenu: React.FC = (props) => {
const menu = items.find((item) => item.path === path);
if (menu) {
setCurrent(menu.key);
}else{
// 如果跳转的详情页面获取根级激活菜单
const rootActiveMenu = path.split('/')[1];
setCurrent(rootActiveMenu);
}
}, [history.location.pathname]);
return (
@ -65,6 +69,7 @@ const HeaderMenu: React.FC = (props) => {
))}
</Menu>
<Language />
<User />
</div>
);
};

View File

@ -5,7 +5,9 @@ const LayoutIndex: React.FC = (props) => {
return (
<>
<Header />
{children}
<div className="layout-content">
<div className='layout-content-main'>{children}</div>
</div>
</>
);
};

11
src/layouts/User.tsx Normal file
View File

@ -0,0 +1,11 @@
import React from 'react';
import { Link, useIntl } from 'umi';
const User: React.FC = (props) => {
const intl = useIntl();
return (
<div className="user">
<Link to={'/login'}>{intl.formatMessage({ id: '登录/注册' })}</Link>
</div>
);
};
export default User;

View File

@ -1,9 +1,90 @@
export default {
'menu.首页': 'home',
'menu.首页': 'Home',
'menu.公告公示': 'Public Announcement',
'menu.政策法规': 'Policies and regulations',
'menu.政策法规': 'Policies and Regulations',
'menu.通知中心': 'Notifications',
'menu.下载中心': 'Download Center',
'menu.关于我们': 'About Us'
'menu.关于我们': 'About Us',
"查看":"Info",
"采购需求公示":"Procurement Demand Announcement",
"招标采购公告":"Bidding Procurement Announcement",
"非招标采购公告":"Non-bidding Procurement Announcement",
"资格预审公告":"Pre-qualification Announcement",
"招募公告":"Recruitment Announcement",
"变更公告":"Change Announcement",
"中标(中选)候选人公示":"Bid Winner Candidate Announcement",
"中标(中选)结果公示":"Bid Result Announcement",
"采购失败(流标)公告":"Failed Procurement Announcement",
"加载更多":"Load More",
"登录/注册":"Login/Register",
// Login page
"login.title": "E-Bidding Platform",
"login.tab.supplier": "Supplier",
"login.tab.expert": "Expert",
"login.tab.agent": "Bidding Agent",
"login.username.placeholder": "Please enter username",
"login.password.placeholder": "Please enter password",
"login.remember": "Remember me",
"login.forgot": "Forgot password?",
"login.button": "Login",
"login.register.tip": "Don't have an account?",
"login.register.action": "Register now",
"login.back.home": "Back to home",
// Registration common text
"register.submit": "Complete Registration",
"register.hasAccount": "Already have an account?",
"register.login": "Login now",
// Username and password common text
"register.username.label": "Username",
"register.username.placeholder": "Please enter username",
"register.username.required": "Please enter username",
"register.username.min": "Username must be at least 4 characters",
"register.password.label": "Password",
"register.password.placeholder": "Please enter password (6-16 characters with letters and numbers)",
"register.password.required": "Please enter password",
"register.password.min": "Password must be at least 6 characters",
"register.password.pattern": "Password must be 6-16 characters with letters and numbers",
"register.confirmPassword.label": "Confirm Password",
"register.confirmPassword.placeholder": "Please confirm password, must match the password above",
"register.confirmPassword.required": "Please confirm password",
"register.confirmPassword.notMatch": "The two passwords do not match",
"register.phone.label": "Phone Number",
"register.phone.placeholder": "Please enter phone number",
"register.phone.required": "Please enter phone number",
"register.phone.invalid": "Please enter a valid phone number",
"register.email.label": "Email",
"register.email.placeholder": "Please enter email",
"register.email.required": "Please enter email",
"register.email.invalid": "Please enter a valid email",
"register.captcha.label": "SMS Verification Code",
"register.captcha.placeholder": "Please enter verification code",
"register.captcha.required": "Please enter verification code",
"register.captcha.get": "Get Code",
// Supplier registration text
"register.supplier.title": "Supplier Registration",
"register.supplier.companyName.label": "Company Name",
"register.supplier.companyName.placeholder": "Please enter company name",
"register.supplier.companyName.required": "Please enter company name",
"register.supplier.contactPerson.label": "Contact Person",
"register.supplier.contactPerson.placeholder": "Please enter contact person",
"register.supplier.contactPerson.required": "Please enter contact person",
// Expert registration text
"register.expert.title": "Expert Registration",
"register.expert.realName.label": "Real Name",
"register.expert.realName.placeholder": "Please enter real name",
"register.expert.realName.required": "Please enter real name",
"register.expert.idType.label": "ID Type",
"register.expert.idType.placeholder": "Please select ID type",
"register.expert.idCard.label": "ID Number",
"register.expert.idCard.placeholder": "Please enter ID number",
"register.expert.idCard.required": "Please enter ID number",
"register.expert.idCard.invalid": "Please enter a valid ID number",
"register.expert.specialty.label": "Specialty Field",
"register.expert.specialty.placeholder": "Please select specialty field",
"register.expert.specialty.required": "Please select specialty field"
};

View File

@ -1,9 +1,90 @@
export default {
'menu.首页': '首页',
'menu.公告公示': '公告公示',
'menu.政策法规': '政策法规',
'menu.通知中心': '通知中心',
'menu.下载中心': '下载中心',
'menu.关于我们': '关于我们'
'menu.关于我们': '关于我们',
"查看":"查看",
"采购需求公示":"采购需求公示",
"招标采购公告":"招标采购公告",
"非招标采购公告":"非招标采购公告",
"资格预审公告":"资格预审公告",
"招募公告":"招募公告",
"变更公告":"变更公告",
"中标(中选)候选人公示":"中标(中选)候选人公示",
"中标(中选)结果公示":"中标(中选)结果公示",
"采购失败(流标)公告":"采购失败(流标)公告",
"加载更多":"加载更多",
"登录/注册":"登录/注册",
// 登录页文案
"login.title": "电子招投标平台",
"login.tab.supplier": "供应商",
"login.tab.expert": "专家",
"login.tab.agent": "招标代理",
"login.username.placeholder": "请输入用户名",
"login.password.placeholder": "请输入密码",
"login.remember": "记住密码",
"login.forgot": "忘记密码?",
"login.button": "登录",
"login.register.tip": "还没有账号?",
"login.register.action": "立即注册",
"login.back.home": "返回首页",
// 注册页通用文案
"register.submit": "注册完成",
"register.hasAccount": "已有账号?",
"register.login": "立即登录",
// 用户名密码通用文案
"register.username.label": "用户名",
"register.username.placeholder": "请输入用户名",
"register.username.required": "请输入用户名",
"register.username.min": "用户名至少4个字符",
"register.password.label": "输入密码",
"register.password.placeholder": "请输入密码应为6-16位的英文加数字组合",
"register.password.required": "请输入密码",
"register.password.min": "密码至少6个字符",
"register.password.pattern": "密码应为6-16位的英文加数字组合",
"register.confirmPassword.label": "确认密码",
"register.confirmPassword.placeholder": "请再次输入密码,两次输入保持一致",
"register.confirmPassword.required": "请确认密码",
"register.confirmPassword.notMatch": "两次输入的密码不一致",
"register.phone.label": "手机号",
"register.phone.placeholder": "请输入手机号",
"register.phone.required": "请输入手机号",
"register.phone.invalid": "请输入有效的手机号",
"register.email.label": "电子邮箱",
"register.email.placeholder": "请输入电子邮箱",
"register.email.required": "请输入电子邮箱",
"register.email.invalid": "请输入有效的电子邮箱",
"register.captcha.label": "短信验证码",
"register.captcha.placeholder": "请输入短信验证码",
"register.captcha.required": "请输入短信验证码",
"register.captcha.get": "获取验证码",
// 供应商注册文案
"register.supplier.title": "供应商注册",
"register.supplier.companyName.label": "公司名称",
"register.supplier.companyName.placeholder": "请输入公司名称",
"register.supplier.companyName.required": "请输入公司名称",
"register.supplier.contactPerson.label": "联系人",
"register.supplier.contactPerson.placeholder": "请输入联系人姓名",
"register.supplier.contactPerson.required": "请输入联系人姓名",
// 专家注册文案
"register.expert.title": "专家注册",
"register.expert.realName.label": "真实姓名",
"register.expert.realName.placeholder": "请输入真实姓名",
"register.expert.realName.required": "请输入真实姓名",
"register.expert.idType.label": "证件类型",
"register.expert.idType.placeholder": "请选择证件类型",
"register.expert.idCard.label": "证件号",
"register.expert.idCard.placeholder": "请输入证件号",
"register.expert.idCard.required": "请输入证件号",
"register.expert.idCard.invalid": "请输入有效的证件号",
"register.expert.specialty.label": "专业领域",
"register.expert.specialty.placeholder": "请选择专业领域",
"register.expert.specialty.required": "请选择专业领域"
};

View File

@ -0,0 +1,8 @@
import React from 'react';
import { useLocation } from 'umi';
const AnnounceInfo: React.FC = () => {
const location = useLocation();
const id = new URLSearchParams(location.search).get("id")
return <>AnnounceInfo -------- {id}</>;
};
export default AnnounceInfo;

17
src/pages/index/Link.tsx Normal file
View File

@ -0,0 +1,17 @@
import React from 'react';
const LinkComponent: React.FC = () => {
return (
<div className="link">
<div></div>
<div className="flex">
<a href="https://www.baidu.com"></a>
<a href="https://www.baidu.com"></a>
<a href="https://www.baidu.com"></a>
<a href="https://www.baidu.com"></a>
<a href="https://www.baidu.com"></a>
</div>
</div>
);
};
export default LinkComponent;

View File

@ -0,0 +1,53 @@
@import '../../baseStyle.less';
.lastDate {
color: @main-danger-color;
}
.tableAddress {
color: @main-color;
font-weight: 600;
}
.tableLoadMore {
margin-top: 15px;
text-align: center;
}
.blockTitle {
font-weight: 600;
font-size: 16px;
line-height: 30px;
}
.questionItem {
line-height: 40px;
.icon {
margin-right: 10px;
font-size: 18px;
}
}
.cardContent {
color: @main-text-color-2;
}
.card {
.ant-card-head {
min-height: 40px;
padding: 0 15px;
.ant-card-head-title,
.ant-card-extra {
padding: 10px 0;
}
}
.ant-card-body {
min-height: 150px;
text-indent: 26px;
}
}
.link {
display: flex;
margin-top: 10px;
.flex {
margin-left: 10px;
display: flex;
flex: 1;
a{
margin: 0 10px;
}
}
}

View File

@ -1,10 +1,247 @@
import React, { useState } from 'react';
import { Card, Row, Col, Tabs, Table } from 'antd';
import { useIntl, Link } from 'umi';
import SpaceBlock from '@/components/SpaceBlock/SpaceBlock';
import './index.less';
import IconFont from '@/components/IconFont/IconFont';
import LinkComponent from './Link';
const IndexPage: React.FC = () => {
const intl = useIntl();
const [noticeLoading, setNoticeLoading] = useState(false);
const [noticeList, setNoticeList] = useState([
{
title: 'CA使用通知',
id: '1',
content: '系统将于2022年5月27日期开始对全流程使用CA服务届时全部投标供应商需办理CA。',
},
{
title: '5月27日系统优化升级通知',
id: '2',
content:
'系统将于2022年5月27日周五22:00--2022年5月28日周六6:00进行系统优化升级届时系统将暂停服务。',
},
{
title: '测试标题123123',
id: '3',
content: '测试内容124145',
},
{
title: '测试标题45435',
id: '4',
content: '测试内容6666',
},
]);
const tabList = [
{
key: '1',
label: intl.formatMessage({ id: '采购需求公示' }),
},
{
key: '2',
label: intl.formatMessage({ id: '招标采购公告' }),
},
{
key: '3',
label: intl.formatMessage({ id: '非招标采购公告' }),
},
{
key: '4',
label: intl.formatMessage({ id: '资格预审公告' }),
},
{
key: '5',
label: intl.formatMessage({ id: '招募公告' }),
},
{
key: '6',
label: intl.formatMessage({ id: '变更公告' }),
},
{
key: '7',
label: intl.formatMessage({ id: '中标(中选)候选人公示' }),
},
{
key: '8',
label: intl.formatMessage({ id: '中标(中选)结果公示' }),
},
{
key: '9',
label: intl.formatMessage({ id: '采购失败(流标)公告' }),
},
];
//tab 切换事件
const tabChange = (key: string) => {
console.log(key);
};
const [tableLoading, setTableLoading] = useState(false);
const dataSource = [
{
key: '1',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
{
key: '2',
title: '中远海运空运北方物流基地标识制作及安装服务',
address: '西湖区湖底公园1号',
date: '2025年01月23日',
lastDate: '剩余3天4小时',
},
];
const columns = [
{
title: '项目所在地',
dataIndex: 'address',
key: 'address',
},
{
title: '公告标题',
dataIndex: 'title',
key: 'title',
render: (text: string, record) => (
<Link
to={{
pathname: '/announce/announceInfo',
search: '?id=' + record.id,
}}
>
{text}
</Link>
),
},
{
title: '发布时间',
dataIndex: 'date',
key: 'date',
},
{
title: '文件购买截止时间',
dataIndex: 'lastDate',
key: 'lastDate',
render: (text: string) => <span className="lastDate">{text}</span>,
},
];
import React from 'react';
const IndexPage:React.FC = () => {
return (
<div>IndexPage</div>
)
}
<div>
{/* 通知列表 */}
<Row gutter={20}>
{noticeList.map((item) => (
<Col span={6} key={item.id}>
<Card
title={item.title}
loading={noticeLoading}
hoverable
className="card"
bodyStyle={{ padding: 10 }}
extra={
<Link
to={{
pathname: '/notice/noticeInfo',
search: '?id=' + item.id,
}}
>
{intl.formatMessage({ id: '查看' })}
</Link>
}
>
<p className="cardContent">{item.content}</p>
</Card>
</Col>
))}
</Row>
<SpaceBlock />
<Tabs onChange={tabChange}>
{tabList.map((item) => (
<Tabs.TabPane tab={item.label} key={item.key} />
))}
</Tabs>
<Table loading={tableLoading} dataSource={dataSource} columns={columns} pagination={false} />
<div className="tableLoadMore">
<Link
to={{
pathname: '/announce',
}}
>
{intl.formatMessage({ id: '加载更多' })}
</Link>
</div>
<Row style={{ marginTop: '20px' }}>
<Col span={12}>
<div className="blockTitle"></div>
<img src="" alt="" />
<div className="questionItem">
<IconFont type="icon-dizhi" className="icon" />
173
</div>
<div className="questionItem">
<IconFont type="icon-dianhua" className="icon" />
17676373746
</div>
<div className="questionItem">
<IconFont type="icon-youxiang" className="icon" />
i723648723@383.com
</div>
</Col>
<Col span={12}>
<div className="blockTitle">CA服务</div>
<Row>
<Col span={6} offset={6}>
<span>CA办理</span>
</Col>
<Col span={6}>
<span>CA客服</span>
</Col>
</Row>
<div className="blockTitle"></div>
<p style={{ marginTop: 20 }}>客服1: 400-300-9989</p>
<p>客服1: 400-300-9989</p>
<p>客服1: 400-300-9989</p>
<p>客服1: 400-300-9989</p>
</Col>
</Row>
<SpaceBlock />
<div>
<LinkComponent />
</div>
</div>
);
};
export default IndexPage;

View File

@ -1,10 +0,0 @@
import React from 'react';
const LoginPage:React.FC = () => {
return (
<div>LoginPage</div>
)
}
export default LoginPage;

194
src/pages/login/login.less Normal file
View File

@ -0,0 +1,194 @@
@import '~@/baseStyle.less';
// 登录页面整体布局
.login-page {
display: flex;
align-items: center;
justify-content: flex-end;
min-height: 100vh;
padding-right: 10%;
background: #f0f2f5;
background-image: url('~@/assets/img/loginBg.jpg');
background-position: center;
background-size: cover;
}
// 登录容器
.login-container {
position: relative;
width: 400px;
padding: 30px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
// 标题样式
.login-title {
margin-bottom: 20px;
color: @main-color;
font-weight: bold;
font-size: 24px;
text-align: center;
}
// 返回首页链接
.back-home {
position: absolute;
top: 10px;
left: 10px;
a {
display: flex;
align-items: center;
color: @main-color;
font-size: 14px;
&:hover {
color: lighten(@main-color, 10%);
}
.anticon {
margin-right: 4px;
}
}
}
// Tab 容器
.login-tab-container {
margin-bottom: 30px;
}
// Tab 样式
.login-tabs {
border-radius: 15px;
.ant-tabs-nav {
margin: 0;
}
.ant-tabs-nav::before {
display: none;
}
.ant-tabs-tab {
flex: 1;
height: 44px;
margin: 0;
padding: 0;
font-weight: bold;
font-size: 16px;
line-height: 44px;
text-align: center;
background-color: #f5f5f5;
border: none;
transition: none;
.ant-tabs-tab-btn {
width: 100%;
height: 100%;
color: #333;
}
}
.ant-tabs-nav-list {
display: flex;
width: 100%;
overflow: hidden;
}
.ant-tabs-tab-active {
background-color: @main-color;
border-radius: 15px;
.ant-tabs-tab-btn {
color: #fff !important;
font-weight: bold;
}
}
.ant-tabs-ink-bar {
display: none;
}
}
// 登录表单
.login-form {
.ant-form-item {
margin-bottom: 20px;
}
.ant-input-affix-wrapper {
border-radius: 10px;
&:focus,
&-focused,
&:hover {
border-color: @main-color;
}
}
}
// 登录选项区域(记住密码和忘记密码)
.login-options {
display: flex;
align-items: center;
justify-content: space-between;
.ant-checkbox-checked .ant-checkbox-inner {
background-color: @main-color;
border-color: @main-color;
}
.login-form-forgot {
color: @main-color;
&:hover {
color: lighten(@main-color, 10%);
}
}
}
// 登录按钮
.login-form-button {
width: 100%;
height: 40px;
margin-top: 10px;
background-color: @main-color;
border-color: @main-color;
border-radius: 4px;
&:hover,
&:focus {
background-color: lighten(@main-color, 10%);
border-color: lighten(@main-color, 10%);
}
}
// 注册链接
.register-link {
margin-top: 15px;
text-align: center;
a {
margin-left: 5px;
color: @main-color;
&:hover {
color: lighten(@main-color, 10%);
}
}
}
// 响应式布局
@media (max-width: 768px) {
.login-page {
justify-content: center;
padding-right: 0;
}
.login-container {
width: 90%;
max-width: 400px;
padding: 20px;
}
}

134
src/pages/login/login.tsx Normal file
View File

@ -0,0 +1,134 @@
import React, { useState } from 'react';
import { Form, Input, Button, Checkbox, Tabs, message } from 'antd';
import { UserOutlined, LockOutlined, EyeInvisibleOutlined, EyeTwoTone, HomeOutlined } from '@ant-design/icons';
import { history, useIntl } from 'umi';
import './login.less';
const { TabPane } = Tabs;
const LoginPage: React.FC = () => {
const [activeKey, setActiveKey] = useState('supplier');
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const intl = useIntl();
const onFinish = (values: any) => {
setLoading(true);
console.log('登录信息:', values);
// 这里添加登录逻辑
setTimeout(() => {
setLoading(false);
message.success('登录成功');
history.push('/index');
}, 1000);
};
const handleTabChange = (key: string) => {
setActiveKey(key);
form.resetFields();
};
// 根据当前选中的Tab决定跳转到哪个注册页面
const handleRegister = () => {
switch(activeKey) {
case 'supplier':
history.push('/register/supplier');
break;
case 'expert':
history.push('/register/expert');
break;
default:
// 招标代理不提供注册功能
break;
}
};
// 渲染注册链接只在供应商和专家Tab下显示
const renderRegisterLink = () => {
if (activeKey === 'agent') {
return null; // 招标代理不显示注册链接
}
return (
<div className="register-link">
{intl.formatMessage({ id: 'login.register.tip' })}
<a onClick={handleRegister}>
{intl.formatMessage({ id: 'login.register.action' })}
</a>
</div>
);
};
return (
<div className='login-page'>
<div className='login-container'>
<div className='back-home'>
<a onClick={() => history.push('/index')}>
<HomeOutlined /> {intl.formatMessage({ id: 'login.back.home' })}
</a>
</div>
<div className='login-title'>{intl.formatMessage({ id: 'login.title' })}</div>
<div className="login-tab-container">
<Tabs activeKey={activeKey} onChange={handleTabChange} className='login-tabs'>
<TabPane tab={intl.formatMessage({ id: 'login.tab.supplier' })} key="supplier" />
<TabPane tab={intl.formatMessage({ id: 'login.tab.expert' })} key="expert" />
<TabPane tab={intl.formatMessage({ id: 'login.tab.agent' })} key="agent" />
</Tabs>
</div>
<Form
form={form}
name="login"
className='login-form'
initialValues={{ remember: false }}
onFinish={onFinish}
>
<Form.Item
name="username"
rules={[{ required: true, message: intl.formatMessage({ id: 'login.username.placeholder' }) + '!' }]}
>
<Input
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder={intl.formatMessage({ id: 'login.username.placeholder' })}
size="large"
/>
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: intl.formatMessage({ id: 'login.password.placeholder' }) + '!' }]}
>
<Input.Password
prefix={<LockOutlined className="site-form-item-icon" />}
placeholder={intl.formatMessage({ id: 'login.password.placeholder' })}
iconRender={visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)}
size="large"
/>
</Form.Item>
<Form.Item>
<div className='login-options'>
<Form.Item name="remember" valuePropName="checked" noStyle>
<Checkbox>{intl.formatMessage({ id: 'login.remember' })}</Checkbox>
</Form.Item>
<a className="login-form-forgot" href="">
{intl.formatMessage({ id: 'login.forgot' })}
</a>
</div>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" className="login-form-button" loading={loading} size="large">
{intl.formatMessage({ id: 'login.button' })}
</Button>
{renderRegisterLink()}
</Form.Item>
</Form>
</div>
</div>
);
};
export default LoginPage;

View File

@ -0,0 +1,8 @@
import React from 'react';
import { useLocation } from 'umi';
const NoticeInfo: React.FC = () => {
const location = useLocation();
const id = new URLSearchParams(location.search).get("id")
return <>NoticeInfo -------- {id}</>;
};
export default NoticeInfo;

View File

@ -0,0 +1,190 @@
import React, { useState } from 'react';
import { useIntl, history } from 'umi';
import { Form, Input, Button, message, Card, Select, Row, Col } from 'antd';
import { UserOutlined, LockOutlined, MobileOutlined, IdcardOutlined, HomeOutlined } from '@ant-design/icons';
import './register.less';
const { Option } = Select;
const ExpertRegister: React.FC = () => {
const [form] = Form.useForm();
const intl = useIntl();
const [loading, setLoading] = useState(false);
const [countdown, setCountdown] = useState(0);
// 获取短信验证码
const handleGetCaptcha = () => {
form.validateFields(['phone']).then(values => {
message.success(`验证码已发送至 ${values.phone}`);
let count = 60;
setCountdown(count);
const timer = setInterval(() => {
count--;
setCountdown(count);
if (count === 0) {
clearInterval(timer);
}
}, 1000);
}).catch(errorInfo => {
message.error('请先输入正确的手机号');
});
};
const onFinish = (values: any) => {
setLoading(true);
console.log('专家注册信息:', values);
// 这里添加注册逻辑
setTimeout(() => {
setLoading(false);
message.success('注册成功,请登录');
history.push('/login');
}, 1000);
};
return (
<div className="register-page">
<div className="register-container">
<div className='back-home'>
<a onClick={() => history.push('/index')}>
<HomeOutlined /> {intl.formatMessage({ id: 'login.back.home' })}
</a>
</div>
<div className="register-title">
{intl.formatMessage({ id: 'register.expert.title' })}
</div>
<Card className="register-card">
<Form
form={form}
name="expert_register"
className="register-form"
onFinish={onFinish}
layout="vertical"
>
<Form.Item
name="username"
label={<span className="required-label">{intl.formatMessage({ id: 'register.username.label' })}</span>}
rules={[
{ required: true, message: intl.formatMessage({ id: 'register.username.required' }) },
{ min: 4, message: intl.formatMessage({ id: 'register.username.min' }) }
]}
>
<Input prefix={<UserOutlined />} placeholder={intl.formatMessage({ id: 'register.username.placeholder' })} />
</Form.Item>
<Form.Item
name="phone"
label={<span className="required-label">{intl.formatMessage({ id: 'register.phone.label' })}</span>}
rules={[
{ required: true, message: intl.formatMessage({ id: 'register.phone.required' }) },
{ pattern: /^1[3-9]\d{9}$/, message: intl.formatMessage({ id: 'register.phone.invalid' }) }
]}
>
<Input prefix={<MobileOutlined />} placeholder={intl.formatMessage({ id: 'register.phone.placeholder' })} />
</Form.Item>
<Form.Item
name="idType"
label={intl.formatMessage({ id: 'register.expert.idType.label' })}
>
<Select placeholder={intl.formatMessage({ id: 'register.expert.idType.placeholder' })}>
<Option value="idcard"></Option>
<Option value="passport"></Option>
<Option value="other"></Option>
</Select>
</Form.Item>
<Form.Item
name="idCard"
label={<span className="required-label">{intl.formatMessage({ id: 'register.expert.idCard.label' })}</span>}
rules={[
{ required: true, message: intl.formatMessage({ id: 'register.expert.idCard.required' }) }
]}
>
<Input prefix={<IdcardOutlined />} placeholder={intl.formatMessage({ id: 'register.expert.idCard.placeholder' })} />
</Form.Item>
<Form.Item
name="password"
label={<span className="required-label">{intl.formatMessage({ id: 'register.password.label' })}</span>}
rules={[
{ required: true, message: intl.formatMessage({ id: 'register.password.required' }) },
{ min: 6, message: intl.formatMessage({ id: 'register.password.min' }) },
{ pattern: /^[a-zA-Z0-9]{6,16}$/, message: intl.formatMessage({ id: 'register.password.pattern' }) }
]}
>
<Input.Password
prefix={<LockOutlined />}
placeholder={intl.formatMessage({ id: 'register.password.placeholder' })}
/>
</Form.Item>
<Form.Item
name="confirmPassword"
label={<span className="required-label">{intl.formatMessage({ id: 'register.confirmPassword.label' })}</span>}
dependencies={['password']}
rules={[
{ required: true, message: intl.formatMessage({ id: 'register.confirmPassword.required' }) },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('password') === value) {
return Promise.resolve();
}
return Promise.reject(new Error(intl.formatMessage({ id: 'register.confirmPassword.notMatch' })));
},
}),
]}
>
<Input.Password
prefix={<LockOutlined />}
placeholder={intl.formatMessage({ id: 'register.confirmPassword.placeholder' })}
/>
</Form.Item>
<Form.Item
name="captcha"
label={<span className="required-label">{intl.formatMessage({ id: 'register.captcha.label' })}</span>}
rules={[{ required: true, message: intl.formatMessage({ id: 'register.captcha.required' }) }]}
>
<Row gutter={8}>
<Col span={16}>
<Input placeholder={intl.formatMessage({ id: 'register.captcha.placeholder' })} />
</Col>
<Col span={8}>
<Button
className="captcha-button"
disabled={countdown > 0}
onClick={handleGetCaptcha}
>
{countdown > 0 ? `${countdown}s` : intl.formatMessage({ id: 'register.captcha.get' })}
</Button>
</Col>
</Row>
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
className="register-button"
loading={loading}
>
{intl.formatMessage({ id: 'register.submit' })}
</Button>
<div className="login-link">
{intl.formatMessage({ id: 'register.hasAccount' })}
<a onClick={() => history.push('/login')}>
{intl.formatMessage({ id: 'register.login' })}
</a>
</div>
</Form.Item>
</Form>
</Card>
</div>
</div>
);
};
export default ExpertRegister;

View File

@ -0,0 +1,162 @@
@import '~@/baseStyle.less';
// 注册页面整体布局
.register-page {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #f0f2f5;
background-image: url('~@/assets/img/loginBg.jpg');
background-size: cover;
background-position: center;
}
// 注册容器
.register-container {
width: 600px;
padding: 30px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
position: relative;
margin: 40px 0;
}
// 标题样式
.register-title {
margin-bottom: 20px;
color: @main-color;
font-weight: bold;
font-size: 24px;
text-align: center;
}
// 返回首页链接
.back-home {
position: absolute;
top: 10px;
left: 10px;
a {
display: flex;
align-items: center;
color: @main-color;
font-size: 14px;
&:hover {
color: lighten(@main-color, 10%);
}
.anticon {
margin-right: 4px;
}
}
}
// 注册卡片
.register-card {
border-radius: 8px;
box-shadow: none;
.ant-card-body {
padding: 20px 0;
}
}
// 必填字段标记
.required-label::before {
display: inline-block;
margin-right: 4px;
color: #ff4d4f;
font-size: 14px;
font-family: SimSun, sans-serif;
line-height: 1;
content: '*';
}
// 注册表单
.register-form {
.ant-form-item {
margin-bottom: 20px;
}
.ant-input,
.ant-input-affix-wrapper,
.ant-select-selector {
border-radius: 6px;
&:focus,
&-focused,
&:hover {
border-color: @main-color;
}
}
.ant-form-item-label > label {
font-weight: 500;
}
}
// 验证码按钮
.captcha-button {
width: 100%;
height: 40px;
background-color: @main-color;
border-color: @main-color;
color: #fff;
&:hover,
&:focus {
background-color: lighten(@main-color, 10%);
border-color: lighten(@main-color, 10%);
color: #fff;
}
&:disabled {
color: rgba(0, 0, 0, 0.25);
background-color: #f5f5f5;
border-color: #d9d9d9;
}
}
// 注册按钮
.register-button {
width: 100%;
height: 40px;
margin-top: 10px;
background-color: @main-color;
border-color: @main-color;
border-radius: 6px;
&:hover,
&:focus {
background-color: lighten(@main-color, 10%);
border-color: lighten(@main-color, 10%);
}
}
// 登录链接
.login-link {
margin-top: 15px;
text-align: center;
a {
margin-left: 5px;
color: @main-color;
&:hover {
color: lighten(@main-color, 10%);
}
}
}
// 响应式布局
@media (max-width: 768px) {
.register-container {
width: 90%;
max-width: 500px;
padding: 20px;
margin: 20px 0;
}
}

View File

@ -0,0 +1,136 @@
import React from 'react';
import { useIntl, history } from 'umi';
import { Form, Input, Button, message, Card } from 'antd';
import { UserOutlined, LockOutlined, MobileOutlined, MailOutlined, HomeOutlined } from '@ant-design/icons';
import './register.less';
const SupplierRegister: React.FC = () => {
const [form] = Form.useForm();
const intl = useIntl();
const onFinish = (values: any) => {
console.log('供应商注册信息:', values);
// 这里添加注册逻辑
message.success('注册成功,请登录');
history.push('/login');
};
return (
<div className="register-page">
<div className="register-container">
<div className='back-home'>
<a onClick={() => history.push('/index')}>
<HomeOutlined /> {intl.formatMessage({ id: 'login.back.home' })}
</a>
</div>
<div className="register-title">
{intl.formatMessage({ id: 'register.supplier.title' })}
</div>
<Card className="register-card">
<Form
form={form}
name="supplier_register"
className="register-form"
onFinish={onFinish}
layout="vertical"
>
<Form.Item
name="username"
label={intl.formatMessage({ id: 'register.username.label' })}
rules={[
{ required: true, message: intl.formatMessage({ id: 'register.username.required' }) },
{ min: 4, message: intl.formatMessage({ id: 'register.username.min' }) }
]}
>
<Input prefix={<UserOutlined />} placeholder={intl.formatMessage({ id: 'register.username.placeholder' })} />
</Form.Item>
<Form.Item
name="password"
label={intl.formatMessage({ id: 'register.password.label' })}
rules={[
{ required: true, message: intl.formatMessage({ id: 'register.password.required' }) },
{ min: 6, message: intl.formatMessage({ id: 'register.password.min' }) }
]}
>
<Input.Password prefix={<LockOutlined />} placeholder={intl.formatMessage({ id: 'register.password.placeholder' })} />
</Form.Item>
<Form.Item
name="confirmPassword"
label={intl.formatMessage({ id: 'register.confirmPassword.label' })}
dependencies={['password']}
rules={[
{ required: true, message: intl.formatMessage({ id: 'register.confirmPassword.required' }) },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('password') === value) {
return Promise.resolve();
}
return Promise.reject(new Error(intl.formatMessage({ id: 'register.confirmPassword.notMatch' })));
},
}),
]}
>
<Input.Password prefix={<LockOutlined />} placeholder={intl.formatMessage({ id: 'register.confirmPassword.placeholder' })} />
</Form.Item>
<Form.Item
name="companyName"
label={intl.formatMessage({ id: 'register.supplier.companyName.label' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'register.supplier.companyName.required' }) }]}
>
<Input placeholder={intl.formatMessage({ id: 'register.supplier.companyName.placeholder' })} />
</Form.Item>
<Form.Item
name="contactPerson"
label={intl.formatMessage({ id: 'register.supplier.contactPerson.label' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'register.supplier.contactPerson.required' }) }]}
>
<Input placeholder={intl.formatMessage({ id: 'register.supplier.contactPerson.placeholder' })} />
</Form.Item>
<Form.Item
name="phone"
label={intl.formatMessage({ id: 'register.phone.label' })}
rules={[
{ required: true, message: intl.formatMessage({ id: 'register.phone.required' }) },
{ pattern: /^1[3-9]\d{9}$/, message: intl.formatMessage({ id: 'register.phone.invalid' }) }
]}
>
<Input prefix={<MobileOutlined />} placeholder={intl.formatMessage({ id: 'register.phone.placeholder' })} />
</Form.Item>
<Form.Item
name="email"
label={intl.formatMessage({ id: 'register.email.label' })}
rules={[
{ type: 'email', message: intl.formatMessage({ id: 'register.email.invalid' }) },
{ required: true, message: intl.formatMessage({ id: 'register.email.required' }) }
]}
>
<Input prefix={<MailOutlined />} placeholder={intl.formatMessage({ id: 'register.email.placeholder' })} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" className="register-button">
{intl.formatMessage({ id: 'register.submit' })}
</Button>
<div className="login-link">
{intl.formatMessage({ id: 'register.hasAccount' })}
<a onClick={() => history.push('/login')}>
{intl.formatMessage({ id: 'register.login' })}
</a>
</div>
</Form.Item>
</Form>
</Card>
</div>
</div>
);
};
export default SupplierRegister;