save
This commit is contained in:
parent
4ca125387e
commit
bc67d4a21d
24
src/App.tsx
24
src/App.tsx
|
|
@ -31,6 +31,28 @@ function App() {
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const getCategoryList = useCallback(async () => {
|
||||||
|
const results = await Promise.allSettled(
|
||||||
|
['news', 'job_type', 'job_area', 'job_unit', "file"]
|
||||||
|
.map(async (type) => {
|
||||||
|
const res = await appApi.getCategoryList(type);
|
||||||
|
return res.data.items.map((item:any) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
).then((results) => {
|
||||||
|
return results.map((result:any) => {
|
||||||
|
return result.value;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const categoryList = results.flat(Infinity)
|
||||||
|
useStore.getState().setCategoryList(categoryList);
|
||||||
|
}, [])
|
||||||
|
|
||||||
const getAppConfig = useCallback(async () => {
|
const getAppConfig = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const res = await appApi.getAppConfig();
|
const res = await appApi.getAppConfig();
|
||||||
|
|
@ -44,6 +66,8 @@ function App() {
|
||||||
];
|
];
|
||||||
useStore.getState().setSupportLocales(supportLocales);
|
useStore.getState().setSupportLocales(supportLocales);
|
||||||
initState(config);
|
initState(config);
|
||||||
|
|
||||||
|
await getCategoryList()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,11 @@ const app = {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getDocList() {
|
getDocList(params: any) {
|
||||||
return requests({
|
return requests({
|
||||||
url: "/yt/api/doc",
|
url: "/yt/api/doc",
|
||||||
method: "get",
|
method: "get",
|
||||||
params: {
|
params: params
|
||||||
page: 1,
|
|
||||||
size: 1000,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 历程列表
|
// 历程列表
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,17 @@
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
||||||
|
.cardImage {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.cardVideo {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.cardMask {
|
.cardMask {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -20,6 +31,7 @@
|
||||||
.cardTitle span {
|
.cardTitle span {
|
||||||
left: 30px;
|
left: 30px;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
|
text-align: left;
|
||||||
transition-delay: 0s;
|
transition-delay: 0s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -45,8 +57,6 @@
|
||||||
transition-delay: 0.2s;
|
transition-delay: 0.2s;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(100% - 170px);
|
top: calc(100% - 170px);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardTitle {
|
.cardTitle {
|
||||||
|
|
@ -61,11 +71,20 @@
|
||||||
padding: 0 30px;
|
padding: 0 30px;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
|
display: inline-block;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
transition-delay: 0.2s;
|
transition-delay: 0.2s;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
|
width: max-content;
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,38 @@
|
||||||
import styles from './index.module.css';
|
import styles from './index.module.css';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useStore } from '@/store';
|
||||||
type Data = {
|
type Data = {
|
||||||
title: string;
|
title: string;
|
||||||
content: string;
|
content: string;
|
||||||
backgroundImage: string;
|
image: string;
|
||||||
|
video: string;
|
||||||
path: string;
|
path: string;
|
||||||
moreText: string;
|
moreText: 'moreText';
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AnimateTopCard({ data }: { data: Data }) {
|
export default function AnimateTopCard({ data }: { data: Data }) {
|
||||||
|
const appConfig = useStore((s) => s.appConfig);
|
||||||
|
const others = appConfig?.__global__?.others ?? {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.card} style={{ backgroundImage: `url(${data.backgroundImage})` }}>
|
<div className={styles.card}>
|
||||||
<div className={styles.cardMask}></div>
|
{
|
||||||
<div className={styles.cardInner}>
|
data.image ?
|
||||||
|
<img src={data.image} alt={data.title} className={styles.cardImage} /> :
|
||||||
|
<video src={data.video} autoPlay muted loop className={styles.cardVideo} />
|
||||||
|
}
|
||||||
|
<div className={styles.cardMask}></div>
|
||||||
|
<div className={styles.cardInner}>
|
||||||
<div className={styles.cardTitle}><span>{data.title}</span></div>
|
<div className={styles.cardTitle}><span>{data.title}</span></div>
|
||||||
<div className={styles.cardTitleUnderline}></div>
|
<div className={styles.cardTitleUnderline}></div>
|
||||||
<div className={styles.cardContent}>
|
<div className={styles.cardContent}>
|
||||||
<div>{data.content}</div>
|
<div dangerouslySetInnerHTML={{__html: data.content}}></div>
|
||||||
<Link to={data.path} className={styles.cardMore}>{data.moreText}</Link>
|
{
|
||||||
|
data.moreText &&
|
||||||
|
<Link to={data.path} className={styles.cardMore}>{others[data.moreText]}</Link>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -23,16 +23,19 @@
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 0%;
|
height: 0%;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
transition: height 0.7s ease-in-out;
|
transition: height 0.5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.showDropPanel.header::before {
|
.showDropPanel.header::before {
|
||||||
height: 350%;
|
height: 100%;
|
||||||
|
transition: height 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.whiteMode.header::before {
|
.whiteMode.header::before {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
@ -44,11 +47,25 @@
|
||||||
transition-delay: none;
|
transition-delay: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.whiteMode .navLink, .showDropPanel .navLink {
|
.keepNavDark.header::before {
|
||||||
color: #222222;
|
height: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.whiteMode, .showDropPanel {
|
.whiteMode .navLink,
|
||||||
|
.showDropPanel .navLink,
|
||||||
|
.keepNavDark .navLink,
|
||||||
|
.keepNavDark .langTrigger,
|
||||||
|
.keepNavDark .searchBtn,
|
||||||
|
.keepNavDark svg {
|
||||||
|
color: #222222;
|
||||||
|
/* transition: color 0.3s ease-in-out; */
|
||||||
|
}
|
||||||
|
.keepNavDark svg path {
|
||||||
|
fill: #222222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.whiteMode,
|
||||||
|
.showDropPanel {
|
||||||
.searchBtn {
|
.searchBtn {
|
||||||
color: #222222;
|
color: #222222;
|
||||||
}
|
}
|
||||||
|
|
@ -89,21 +106,27 @@
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
transform: scaleX(0);
|
transform: scaleX(0);
|
||||||
transform-origin: 90% 0; /* 交点:左侧 85%,右侧 15%,从此点向左右展开 */
|
transform-origin: 90% 0;
|
||||||
|
/* 交点:左侧 85%,右侧 15%,从此点向左右展开 */
|
||||||
transition: transform 1.5s ease-in-out;
|
transition: transform 1.5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.animate {
|
.animate {
|
||||||
&.headerInner::after {
|
&.headerInner::after {
|
||||||
transform: scaleX(1);
|
transform: scaleX(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.crossYline {
|
.crossYline {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.whiteMode, .showDropPanel {
|
|
||||||
|
.whiteMode,
|
||||||
|
.showDropPanel {
|
||||||
.headerInner::after {
|
.headerInner::after {
|
||||||
transform: scaleX(0);
|
transform: scaleX(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.crossYline {
|
.crossYline {
|
||||||
height: 0%;
|
height: 0%;
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +139,12 @@
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commonMode {
|
||||||
|
.logo img {
|
||||||
|
transition: filter 0.5s steps(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.headerRight {
|
.headerRight {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -152,6 +181,7 @@
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -164,8 +194,10 @@
|
||||||
width: 1px;
|
width: 1px;
|
||||||
height: 0%;
|
height: 0%;
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
align-self: flex-end; /* 交点在最底部,从此点向上展开 */
|
align-self: flex-end;
|
||||||
transform-origin: center bottom; /* 缩放从底部中心点展开 */
|
/* 交点在最底部,从此点向上展开 */
|
||||||
|
transform-origin: center bottom;
|
||||||
|
/* 缩放从底部中心点展开 */
|
||||||
transition: height 1s ease-in-out;
|
transition: height 1s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,16 +229,18 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 0;
|
height: 0;
|
||||||
/* background: rgba(255, 255, 255, 0.9); */
|
background: rgba(255, 255, 255, 0.9);
|
||||||
/* box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1); */
|
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: height 0.5s ease-in-out, padding-top 0.5s ease-in-out;
|
transition: height 0.5s ease-in-out, padding-top 0.5s ease-in-out;
|
||||||
|
/* transition-delay: 0.45s; */
|
||||||
|
|
||||||
&.visible {
|
&.visible {
|
||||||
height: 23.75rem;
|
height: 23.75rem;
|
||||||
padding-top: 1.25rem;
|
padding-top: 1.25rem;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ export default function Header() {
|
||||||
|
|
||||||
const [activeNav, setActiveNav] = useState("");
|
const [activeNav, setActiveNav] = useState("");
|
||||||
const [showDropPanel, setShowDropPanel] = useState(false);
|
const [showDropPanel, setShowDropPanel] = useState(false);
|
||||||
|
const [keepNavDark, setKeepNavDark] = useState(false);
|
||||||
|
const leaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
const [hoverElLeft, setHoverElLeft] = useState(0);
|
const [hoverElLeft, setHoverElLeft] = useState(0);
|
||||||
const handleNavEnter = (e: any, path: string) => {
|
const handleNavEnter = (e: any, path: string) => {
|
||||||
const left = e.target.offsetLeft;
|
const left = e.target.offsetLeft;
|
||||||
|
|
@ -29,6 +31,11 @@ export default function Header() {
|
||||||
setHoverElLeft(left + width / 2);
|
setHoverElLeft(left + width / 2);
|
||||||
setActiveNav(path);
|
setActiveNav(path);
|
||||||
setShowDropPanel(true);
|
setShowDropPanel(true);
|
||||||
|
setKeepNavDark(true);
|
||||||
|
if (leaveTimerRef.current) {
|
||||||
|
clearTimeout(leaveTimerRef.current);
|
||||||
|
leaveTimerRef.current = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const activePanelItem = useMemo(() => {
|
const activePanelItem = useMemo(() => {
|
||||||
|
|
@ -65,12 +72,33 @@ export default function Header() {
|
||||||
}, 500);
|
}, 500);
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const handleHeaderMouseLeave = () => {
|
||||||
|
setShowDropPanel(false);
|
||||||
|
if (leaveTimerRef.current) {
|
||||||
|
clearTimeout(leaveTimerRef.current);
|
||||||
|
}
|
||||||
|
leaveTimerRef.current = setTimeout(() => {
|
||||||
|
setKeepNavDark(false);
|
||||||
|
leaveTimerRef.current = null;
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleHeaderMouseEnter = () => {
|
||||||
|
if (leaveTimerRef.current) {
|
||||||
|
clearTimeout(leaveTimerRef.current);
|
||||||
|
leaveTimerRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className={`${styles.header}
|
<header className={`${styles.header}
|
||||||
${showWhiteMode && styles.whiteMode}
|
${showWhiteMode ? styles.whiteMode : ''}
|
||||||
${showDropPanel && styles.showDropPanel}
|
${showDropPanel ? styles.showDropPanel : ''}
|
||||||
|
${keepNavDark ? styles.keepNavDark : ''}
|
||||||
|
${!showWhiteMode && !showDropPanel ? styles.commonMode : ''}
|
||||||
`}
|
`}
|
||||||
onMouseLeave={() => setShowDropPanel(false)}
|
onMouseLeave={handleHeaderMouseLeave}
|
||||||
|
onMouseEnter={handleHeaderMouseEnter}
|
||||||
>
|
>
|
||||||
<div className={`header-row ${styles.headerInner} ${animateHeader ? styles.animate : ""}`}>
|
<div className={`header-row ${styles.headerInner} ${animateHeader ? styles.animate : ""}`}>
|
||||||
<Link to="/" className={styles.logo}>
|
<Link to="/" className={styles.logo}>
|
||||||
|
|
@ -117,7 +145,12 @@ export default function Header() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DropPanel items={activePanelItem} left={hoverElLeft}
|
<DropPanel items={activePanelItem} left={hoverElLeft}
|
||||||
onLinkClick={() => setShowDropPanel(false)}
|
onLinkClick={() => {
|
||||||
|
setShowDropPanel(false)
|
||||||
|
setTimeout(() => {
|
||||||
|
setKeepNavDark(false);
|
||||||
|
}, 500);
|
||||||
|
}}
|
||||||
show={showDropPanel && activePanelItem.length > 0}
|
show={showDropPanel && activePanelItem.length > 0}
|
||||||
/>
|
/>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ export default function Home() {
|
||||||
|
|
||||||
function News() {
|
function News() {
|
||||||
const locale = useStore((s) => s.locale);
|
const locale = useStore((s) => s.locale);
|
||||||
|
const categoryList = useStore((s) => s.categoryList);
|
||||||
const [newsData, setNewsData] = useState<any[]>([]);
|
const [newsData, setNewsData] = useState<any[]>([]);
|
||||||
const videoRef = useRef<HTMLVideoElement | null>(null);
|
const videoRef = useRef<HTMLVideoElement | null>(null);
|
||||||
const localNewsData = useMemo(() => {
|
const localNewsData = useMemo(() => {
|
||||||
|
|
@ -122,16 +123,10 @@ function News() {
|
||||||
setNewsData(data);
|
setNewsData(data);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
const getCategoryList = useCallback(async () => {
|
|
||||||
const res = await appApi.getCategoryList('news');
|
|
||||||
const category_id = res.data.items.find((item: any) => item.name.includes('新闻资讯'))?.id;
|
|
||||||
return category_id;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getCategoryList().then((category_id) => {
|
const category_id = categoryList?.find((item: any) => item.name === '【首页】新闻资讯')?.id;
|
||||||
handleSearch(category_id)
|
handleSearch(category_id)
|
||||||
});
|
|
||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
<Section title="新闻资讯" maskBackground="#F0F2F4">
|
<Section title="新闻资讯" maskBackground="#F0F2F4">
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,14 @@ type JobItem = {
|
||||||
content: string;
|
content: string;
|
||||||
labels: string[];
|
labels: string[];
|
||||||
lang: string
|
lang: string
|
||||||
}
|
};
|
||||||
|
|
||||||
|
type SelectOption = { label: string; value: string };
|
||||||
|
|
||||||
export default function JoinCampus() {
|
export default function JoinCampus() {
|
||||||
const appConfig = useStore((s) => s.appConfig);
|
const appConfig = useStore((s) => s.appConfig);
|
||||||
const supportLocales = useStore((s) => s.supportLocales);
|
const supportLocales = useStore((s) => s.supportLocales);
|
||||||
|
const categoryList = useStore((s) => s.categoryList);
|
||||||
const locale = useStore((s) => s.locale);
|
const locale = useStore((s) => s.locale);
|
||||||
const data = appConfig?.join?.campus;
|
const data = appConfig?.join?.campus;
|
||||||
const banner = data?.banner;
|
const banner = data?.banner;
|
||||||
|
|
@ -29,11 +32,11 @@ export default function JoinCampus() {
|
||||||
|
|
||||||
// 职业类别 业务领域 所属板块
|
// 职业类别 业务领域 所属板块
|
||||||
const [jobType, setJobType] = useState('');
|
const [jobType, setJobType] = useState('');
|
||||||
const [jobTypeOptions, setJobTypeOptions] = useState([]);
|
const [jobTypeOptions, setJobTypeOptions] = useState<SelectOption[]>([]);
|
||||||
const [businessArea, setBusinessArea] = useState('');
|
const [businessArea, setBusinessArea] = useState('');
|
||||||
const [businessAreaOptions, setBusinessAreaOptions] = useState([]);
|
const [businessAreaOptions, setBusinessAreaOptions] = useState<SelectOption[]>([]);
|
||||||
const [businessPlate, setBusinessPlate] = useState('');
|
const [businessPlate, setBusinessPlate] = useState('');
|
||||||
const [businessPlateOptions, setBusinessPlateOptions] = useState([]);
|
const [businessPlateOptions, setBusinessPlateOptions] = useState<SelectOption[]>([]);
|
||||||
|
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [size] = useState(2 * supportLocales.length);
|
const [size] = useState(2 * supportLocales.length);
|
||||||
|
|
@ -69,20 +72,16 @@ export default function JoinCampus() {
|
||||||
}, 500), []);
|
}, 500), []);
|
||||||
|
|
||||||
const getTypes = useCallback(() => {
|
const getTypes = useCallback(() => {
|
||||||
['job_type', 'job_area', 'job_unit'].forEach(type => {
|
const jobTypeOptions: SelectOption[] =
|
||||||
appApi.getCategoryList(type).then((res) => {
|
categoryList?.filter((item: any) => item.type === 'job_type').map((item: any) => ({ label: item.name, value: String(item.id) })) ?? [];
|
||||||
const items = res.data.items.map((item:any) => ({ label: item.name, value: item.id }));
|
const businessAreaOptions: SelectOption[] =
|
||||||
items.unshift({ label: "全部", value: "" });
|
categoryList?.filter((item: any) => item.type === 'job_area').map((item: any) => ({ label: item.name, value: String(item.id) })) ?? [];
|
||||||
if (type === 'job_type') {
|
const businessPlateOptions: SelectOption[] =
|
||||||
setJobTypeOptions(items);
|
categoryList?.filter((item: any) => item.type === 'job_unit').map((item: any) => ({ label: item.name, value: String(item.id) })) ?? [];
|
||||||
} else if (type === 'job_area') {
|
setJobTypeOptions(jobTypeOptions);
|
||||||
setBusinessAreaOptions(items);
|
setBusinessAreaOptions(businessAreaOptions);
|
||||||
} else if (type === 'job_unit') {
|
setBusinessPlateOptions(businessPlateOptions);
|
||||||
setBusinessPlateOptions(items);
|
}, [categoryList]);
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refreshData();
|
refreshData();
|
||||||
|
|
|
||||||
|
|
@ -21,19 +21,20 @@ export default function NewsPublic() {
|
||||||
const appConfig = useStore((s) => s.appConfig);
|
const appConfig = useStore((s) => s.appConfig);
|
||||||
const locale = useStore((s) => s.locale);
|
const locale = useStore((s) => s.locale);
|
||||||
const supportLocales = useStore((s) => s.supportLocales);
|
const supportLocales = useStore((s) => s.supportLocales);
|
||||||
|
const categoryList = useStore((s) => s.categoryList);
|
||||||
const data = appConfig?.news?.public;
|
const data = appConfig?.news?.public;
|
||||||
|
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [size] = useState(9 * supportLocales.length);
|
const [size] = useState(9 * supportLocales.length);
|
||||||
const [total, setTotal] = useState(0);
|
const [total, setTotal] = useState(0);
|
||||||
const categoryIdRef = useRef<string | null>('');
|
const categoryId = String(categoryList?.find((item: any) => item.name.includes('集团发布'))?.id ?? '');
|
||||||
|
|
||||||
const [newList, setNewList] = useState<NewsItem[]>([]);
|
const [newList, setNewList] = useState<NewsItem[]>([]);
|
||||||
const videoRefs = useRef<(HTMLVideoElement | null)[]>([]);
|
const videoRefs = useRef<(HTMLVideoElement | null)[]>([]);
|
||||||
const [searchValue, setSearchValue] = useState("");
|
const [searchValue, setSearchValue] = useState("");
|
||||||
const handleSearch = useCallback(() => {
|
const handleSearch = useCallback(() => {
|
||||||
appApi.getNewsList({ page, size, sort: "create_time DESC", title: searchValue,
|
appApi.getNewsList({ page, size, sort: "create_time DESC", title: searchValue,
|
||||||
category_id: categoryIdRef.current ?? '',
|
category_id: categoryId,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
const data = res.data.items.map((item:any) => {
|
const data = res.data.items.map((item:any) => {
|
||||||
return {
|
return {
|
||||||
|
|
@ -54,19 +55,10 @@ export default function NewsPublic() {
|
||||||
return newList.filter(item => item.lang.toLowerCase() === locale.split('-')[0]);
|
return newList.filter(item => item.lang.toLowerCase() === locale.split('-')[0]);
|
||||||
}, [newList, locale]);
|
}, [newList, locale]);
|
||||||
|
|
||||||
const getCategoryList = useCallback(async () => {
|
|
||||||
const res = await appApi.getCategoryList('news');
|
|
||||||
const category_id = res.data.items.find((item: any) => item.name.includes('集团发布'))?.id;
|
|
||||||
categoryIdRef.current = category_id;
|
|
||||||
return category_id;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const banner = data?.banner;
|
const banner = data?.banner;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getCategoryList().then(() => {
|
handleSearch();
|
||||||
handleSearch();
|
|
||||||
})
|
|
||||||
}, [page, size]);
|
}, [page, size]);
|
||||||
|
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import Banner, { type BannerConfig } from "@/components/Banner";
|
import Banner, { type BannerConfig } from "@/components/Banner";
|
||||||
import { useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import ParagraphSection from "@/components/layout/ParagraphSection";
|
import ParagraphSection from "@/components/layout/ParagraphSection";
|
||||||
import Section from "@/components/layout/Section";
|
import Section from "@/components/layout/Section";
|
||||||
import AnimateTopCard from "@/components/layout/AnimateTopCard";
|
import AnimateTopCard from "@/components/layout/AnimateTopCard";
|
||||||
|
|
@ -7,20 +7,44 @@ import BottomTabs from "@/components/layout/BottomTabsSection/BottomTabs";
|
||||||
import { useStore } from "@/store";
|
import { useStore } from "@/store";
|
||||||
import styles from "./Foundation.module.css";
|
import styles from "./Foundation.module.css";
|
||||||
import TopTabsSection from "@/components/layout/TopTabsSection";
|
import TopTabsSection from "@/components/layout/TopTabsSection";
|
||||||
|
import appApi from "@/api/app";
|
||||||
export default function Foundation() {
|
export default function Foundation() {
|
||||||
const appConfig = useStore((s) => s.appConfig);
|
const appConfig = useStore((s) => s.appConfig);
|
||||||
const data = appConfig?.social?.foundation;
|
const data = appConfig?.social?.foundation;
|
||||||
|
const locale = useStore((s) => s.locale)
|
||||||
|
const categoryList = useStore((s) => s.categoryList)
|
||||||
const [activeIndex, setActiveIndex] = useState(0);
|
const [activeIndex, setActiveIndex] = useState(0);
|
||||||
|
|
||||||
if (!data) return null;
|
|
||||||
|
|
||||||
const banner = data.banner;
|
const banner = data.banner;
|
||||||
const section1Data = data.section1Data;
|
const section1Data = data.section1Data;
|
||||||
const section2Data = data.section2Data;
|
const section2Data = data.section2Data;
|
||||||
const section3Data = data.section3Data;
|
const section3Data = data.section3Data;
|
||||||
const section4Data = data.section4Data;
|
const section4Data = data.section4Data;
|
||||||
|
|
||||||
|
|
||||||
|
const [newsList, setNewsList] = useState<any[]>([]);
|
||||||
|
const localNewsList = useMemo(() => {
|
||||||
|
return newsList.filter((item: any) => item.lang.toLowerCase() === locale.split('-')[0]);
|
||||||
|
}, [newsList, locale])
|
||||||
|
useEffect(() => {
|
||||||
|
appApi.getNewsList({ page: 1, size: 1000, sort: "create_time DESC",
|
||||||
|
category_id: String(categoryList?.find((item: any) => item.name.includes('【可持续发展】社会责任案例集'))?.id ?? ''),
|
||||||
|
}).then((res:any) => {
|
||||||
|
setNewsList(res.data.items.map((item:any) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
title: item.title,
|
||||||
|
content: item.content,
|
||||||
|
path: item.path,
|
||||||
|
image: item.covers_show === 'image' ? item.covers.image[0] : '',
|
||||||
|
video: item.covers_show === 'video' ? item.covers.video[0] : '',
|
||||||
|
lang: item.lang,
|
||||||
|
moreText: 'moreText',
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Banner
|
<Banner
|
||||||
|
|
@ -43,13 +67,12 @@ export default function Foundation() {
|
||||||
maskBackground="rgba(255,255,255,0.3)"
|
maskBackground="rgba(255,255,255,0.3)"
|
||||||
>
|
>
|
||||||
<div className={styles.publicWelfareDataItems}>
|
<div className={styles.publicWelfareDataItems}>
|
||||||
{section2Data.items?.map((item: { title: string; content?: string; backgroundImage?: string; path?: string; moreText?: string }, index: number) => (
|
{localNewsList?.map((item: any, index: number) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={styles.publicWelfareDataItem}
|
className={styles.publicWelfareDataItem}
|
||||||
style={{ backgroundImage: `url(${item.backgroundImage})` }}
|
|
||||||
>
|
>
|
||||||
<AnimateTopCard data={{ ...item, content: item.content ?? "", path: item.path ?? "", moreText: item.moreText ?? "", backgroundImage: item.backgroundImage ?? "" }} />
|
<AnimateTopCard data={item} />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,7 @@
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.socialResponsibilityReportItemTitle {
|
.socialResponsibilityReportItemTitle {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,30 @@
|
||||||
import Banner, { type BannerConfig } from "@/components/Banner";
|
import Banner, { type BannerConfig } from "@/components/Banner";
|
||||||
import { useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import ParagraphSection from "@/components/layout/ParagraphSection";
|
import ParagraphSection from "@/components/layout/ParagraphSection";
|
||||||
import ColumnXGrids from "@/components/layout/ColumnXGrids";
|
import ColumnXGrids from "@/components/layout/ColumnXGrids";
|
||||||
import Section from "@/components/layout/Section";
|
import Section from "@/components/layout/Section";
|
||||||
import AnimateTopCard from "@/components/layout/AnimateTopCard";
|
import AnimateTopCard from "@/components/layout/AnimateTopCard";
|
||||||
import { useStore } from "@/store";
|
import { useStore } from "@/store";
|
||||||
import styles from "./Sustainability.module.css";
|
import styles from "./Sustainability.module.css";
|
||||||
|
import appApi from "@/api/app";
|
||||||
|
|
||||||
|
type NewsItem = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
createTime: string;
|
||||||
|
image: string;
|
||||||
|
video: string;
|
||||||
|
lang: "ZH" | "EN"
|
||||||
|
}
|
||||||
|
|
||||||
|
const LANG_LEN = 2
|
||||||
|
|
||||||
export default function Sustainability() {
|
export default function Sustainability() {
|
||||||
const appConfig = useStore((s) => s.appConfig);
|
const appConfig = useStore((s) => s.appConfig);
|
||||||
|
const categoryList = useStore((s) => s.categoryList);
|
||||||
|
const locale = useStore((s) => s.locale);
|
||||||
const data = appConfig?.social?.sustainability;
|
const data = appConfig?.social?.sustainability;
|
||||||
const [sliceIndex, setSliceIndex] = useState(4);
|
const others = appConfig?.__global__?.others ?? {};
|
||||||
|
|
||||||
if (!data) return null;
|
|
||||||
|
|
||||||
const banner = data.banner;
|
const banner = data.banner;
|
||||||
const section1Data = data.section1Data;
|
const section1Data = data.section1Data;
|
||||||
|
|
@ -22,6 +34,81 @@ export default function Sustainability() {
|
||||||
|
|
||||||
const columnXGridsData = section2Data;
|
const columnXGridsData = section2Data;
|
||||||
|
|
||||||
|
|
||||||
|
// 社会责任案例新闻数据
|
||||||
|
const [newsItems, setNewsItems] = useState<NewsItem[]>([]);
|
||||||
|
const localNewsItems = useMemo(() => {
|
||||||
|
return newsItems.filter((item: any) => item.lang.toLowerCase() === locale.split('-')[0]);
|
||||||
|
}, [newsItems, locale])
|
||||||
|
|
||||||
|
const getNewsList = useCallback(() => {
|
||||||
|
appApi.getNewsList({
|
||||||
|
page: 1,
|
||||||
|
size: 8,
|
||||||
|
sort: "create_time DESC",
|
||||||
|
category_id: String(categoryList?.find((item: any) => item.name.includes('【可持续发展】社会责任案例集'))?.id ?? ''),
|
||||||
|
}).then((res) => {
|
||||||
|
const items = res.data.items.map((item: any) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
title: item.title,
|
||||||
|
content: item.content,
|
||||||
|
createTime: item.create_time,
|
||||||
|
image: item.covers_show === 'image' ? item.covers.image[0] : '',
|
||||||
|
video: item.covers_show === 'video' ? item.covers.video[0] : '',
|
||||||
|
path: `/news/detail/${item.id}`,
|
||||||
|
lang: item.lang,
|
||||||
|
moreText: 'moreText',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setNewsItems(items as NewsItem[])
|
||||||
|
});
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
// 社会责任报告
|
||||||
|
type ReportItem = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
cover: string;
|
||||||
|
}
|
||||||
|
const [reportItems, setReportItems] = useState<ReportItem[]>([]);
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const [size, setSize] = useState(8);
|
||||||
|
const [total, setTotal] = useState(0);
|
||||||
|
const localReportItems = useMemo(() => {
|
||||||
|
return reportItems.filter((item: any) => item.lang.toLowerCase() === locale.split('-')[0]);
|
||||||
|
}, [reportItems, locale])
|
||||||
|
const getReportList = useCallback(async () => {
|
||||||
|
const res = await appApi.getDocList({
|
||||||
|
page,
|
||||||
|
size,
|
||||||
|
category_id: String(categoryList?.find((item: any) => item.name.includes('社会责任报告'))?.id ?? '')
|
||||||
|
})
|
||||||
|
setTotal(res.data.total / LANG_LEN)
|
||||||
|
setReportItems((prev) => {
|
||||||
|
let items = [...prev, ...res.data.items]
|
||||||
|
const resItems: any[] = []
|
||||||
|
// 去重 id lang 相同
|
||||||
|
items.forEach((item: any) => {
|
||||||
|
if(!resItems.some((i: any) => i.id === item.id && i.lang === item.lang)) {
|
||||||
|
resItems.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log('---resItems', resItems)
|
||||||
|
return resItems
|
||||||
|
})
|
||||||
|
}, [page, size])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getNewsList()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getReportList()
|
||||||
|
}, [page])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Banner
|
<Banner
|
||||||
|
|
@ -47,11 +134,10 @@ export default function Sustainability() {
|
||||||
{section3Data.content}
|
{section3Data.content}
|
||||||
</p>
|
</p>
|
||||||
<div className={styles.socialResponsibilityCaseDataItems}>
|
<div className={styles.socialResponsibilityCaseDataItems}>
|
||||||
{section3Data.items?.map((item: any, index: number) => (
|
{localNewsItems?.map((item: any, index: number) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={styles.socialResponsibilityCaseDataItem}
|
className={styles.socialResponsibilityCaseDataItem}
|
||||||
style={{ backgroundImage: `url(${item.backgroundImage})` }}
|
|
||||||
>
|
>
|
||||||
<AnimateTopCard data={item} />
|
<AnimateTopCard data={item} />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -67,32 +153,36 @@ export default function Sustainability() {
|
||||||
maskBackground="#F7FBFF"
|
maskBackground="#F7FBFF"
|
||||||
>
|
>
|
||||||
<div className={styles.socialResponsibilityReportData}>
|
<div className={styles.socialResponsibilityReportData}>
|
||||||
{section4Data.items?.slice(0, sliceIndex).map((item: any, index: number) => (
|
{localReportItems?.map((item: any, index: number) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={styles.socialResponsibilityReportItem}
|
className={styles.socialResponsibilityReportItem}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={styles.socialResponsibilityReportItemCover}
|
className={styles.socialResponsibilityReportItemCover}
|
||||||
style={{ backgroundImage: `url(${item.coverImage})` }}
|
style={{ backgroundImage: `url(${item.cover})` }}
|
||||||
|
onClick={() => {
|
||||||
|
window.open(item.path, '_blank')
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<div className={styles.socialResponsibilityReportItemTitle}>
|
<div className={styles.socialResponsibilityReportItemTitle}>
|
||||||
{item.title}
|
{item.name}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={styles.socialResponsibilityReportItemMore}
|
className={styles.socialResponsibilityReportItemMore}
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
setSliceIndex(
|
if(localReportItems.length < total) {
|
||||||
sliceIndex < (section4Data.items?.length ?? 0)
|
setPage(page + 1)
|
||||||
? sliceIndex + 4
|
} else {
|
||||||
: 4
|
setReportItems(prev => [...prev.slice(0, 8)])
|
||||||
)
|
setPage(1)
|
||||||
}
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{sliceIndex < (section4Data.items?.length ?? 0) ? "了解更多" : "收起"}
|
{localReportItems.length < total ? "了解更多" : "收起"}
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,16 @@ interface StoreState {
|
||||||
locale: LocaleKey;
|
locale: LocaleKey;
|
||||||
i18nData: I18nData | null;
|
i18nData: I18nData | null;
|
||||||
appConfig: AppConfig | null;
|
appConfig: AppConfig | null;
|
||||||
|
categoryList: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
}[] | null;
|
||||||
supportLocales: SupportLocale[];
|
supportLocales: SupportLocale[];
|
||||||
token: string | null;
|
token: string | null;
|
||||||
setLocale: (locale: LocaleKey) => void;
|
setLocale: (locale: LocaleKey) => void;
|
||||||
setAppConfig: (data: I18nData) => void;
|
setAppConfig: (data: I18nData) => void;
|
||||||
|
setCategoryList: (list: any[]) => void;
|
||||||
setToken: (token: string | null) => void;
|
setToken: (token: string | null) => void;
|
||||||
setSupportLocales: (locales: SupportLocale[]) => void;
|
setSupportLocales: (locales: SupportLocale[]) => void;
|
||||||
}
|
}
|
||||||
|
|
@ -29,6 +35,7 @@ export const useStore = create<StoreState>()(
|
||||||
locale: 'zh-CN',
|
locale: 'zh-CN',
|
||||||
i18nData: null,
|
i18nData: null,
|
||||||
appConfig: null,
|
appConfig: null,
|
||||||
|
categoryList: null,
|
||||||
supportLocales: [],
|
supportLocales: [],
|
||||||
token: null,
|
token: null,
|
||||||
setLocale: (locale) =>
|
setLocale: (locale) =>
|
||||||
|
|
@ -41,6 +48,7 @@ export const useStore = create<StoreState>()(
|
||||||
i18nData: data,
|
i18nData: data,
|
||||||
appConfig: data[state.locale] ?? data['en-US'] ?? data['zh-CN'] ?? null,
|
appConfig: data[state.locale] ?? data['en-US'] ?? data['zh-CN'] ?? null,
|
||||||
})),
|
})),
|
||||||
|
setCategoryList: (list) => set({ categoryList: list }),
|
||||||
setToken: (token) => set({ token }),
|
setToken: (token) => set({ token }),
|
||||||
setSupportLocales: (locales: SupportLocale[]) => set({ supportLocales: locales }),
|
setSupportLocales: (locales: SupportLocale[]) => set({ supportLocales: locales }),
|
||||||
}),
|
}),
|
||||||
|
|
@ -62,6 +70,7 @@ export const useStore = create<StoreState>()(
|
||||||
locale,
|
locale,
|
||||||
i18nData: { "zh-CN": legacy, "en-US": legacy },
|
i18nData: { "zh-CN": legacy, "en-US": legacy },
|
||||||
appConfig: legacy,
|
appConfig: legacy,
|
||||||
|
categoryList: p.categoryList,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
partialize: (s) => ({
|
partialize: (s) => ({
|
||||||
|
|
@ -70,6 +79,7 @@ export const useStore = create<StoreState>()(
|
||||||
token: s.token,
|
token: s.token,
|
||||||
appConfig: s.i18nData?.[s.locale] ?? s.appConfig,
|
appConfig: s.i18nData?.[s.locale] ?? s.appConfig,
|
||||||
supportLocales: s.supportLocales,
|
supportLocales: s.supportLocales,
|
||||||
|
categoryList: s.categoryList,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { useStore } from "zustand";
|
||||||
|
import { LocaleKey } from "@/type";
|
||||||
|
|
||||||
// debounce
|
// debounce
|
||||||
export const debounce = (func: (...args: any[]) => void, delay: number) => {
|
export const debounce = (func: (...args: any[]) => void, delay: number) => {
|
||||||
let timeout: NodeJS.Timeout;
|
let timeout: NodeJS.Timeout;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue