提交 33c5b6b6 作者: ZhangLingKun

功能:新版后台

上级 c36ab974
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
} }
], ],
"react-hooks/rules-of-hooks": "error", "react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn", "react-hooks/exhaustive-deps": "off",
"prettier/prettier": [ "prettier/prettier": [
"warn", "warn",
{ {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
"format": "npm run prettier:fix && npm run lint:fix" "format": "npm run prettier:fix && npm run lint:fix"
}, },
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^1.9.2",
"@ant-design/icons": "^5.0.1", "@ant-design/icons": "^5.0.1",
"antd": "^5.4.2", "antd": "^5.4.2",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
...@@ -28,7 +29,8 @@ ...@@ -28,7 +29,8 @@
"js-base64": "^3.7.3", "js-base64": "^3.7.3",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"qs": "^6.10.3" "qs": "^6.10.3",
"react-redux": "^8.0.5"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.1.3", "@types/node": "^20.1.3",
...@@ -39,6 +41,7 @@ ...@@ -39,6 +41,7 @@
"@vitejs/plugin-react": "^1.3.0", "@vitejs/plugin-react": "^1.3.0",
"@types/js-cookie": "^3.0.1", "@types/js-cookie": "^3.0.1",
"@types/lodash": "^4.14.182", "@types/lodash": "^4.14.182",
"@types/react-redux": "^7.1.25",
"eslint": "^8.16.0", "eslint": "^8.16.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
......
import { PointManageAPI } from './modules/pointManageAPI'; import { PointManageAPI } from './modules/pointManageAPI';
export { export { PointManageAPI };
PointManageAPI,
};
import { import { InterFunction, InterItemFunction, InterListFunction } from '../interface';
InterFunction,
InterItemFunction,
InterListFunction,
} from "../interface";
// 演示规范 // 演示规范
export type PointListType = InterListFunction< export type PointListType = InterListFunction<
...@@ -113,10 +109,7 @@ export type GetUserScoreDetailsType = InterFunction< ...@@ -113,10 +109,7 @@ export type GetUserScoreDetailsType = InterFunction<
>; >;
// 流通方式列表 // 流通方式列表
export type ListCirculateInfoType = InterFunction< export type ListCirculateInfoType = InterFunction<{}, { id: number; type: string }[]>;
{},
{ id: number; type: string }[]
>;
// 积分发放 // 积分发放
export type OrderScoreReleaseType = InterFunction< export type OrderScoreReleaseType = InterFunction<
......
import axios from "../request"; import axios from '../request';
import { import {
AddAndEditBonusRuleType, AddAndEditBonusRuleType,
AddConvertRuleType, AddConvertRuleType,
...@@ -25,106 +25,106 @@ import { ...@@ -25,106 +25,106 @@ import {
UpdateMallOrderBonusType, UpdateMallOrderBonusType,
UserScoreDetailsListType, UserScoreDetailsListType,
UserScorePageListType, UserScorePageListType,
} from "../interface/pointManageType"; } from '../interface/pointManageType';
export class PointManageAPI { export class PointManageAPI {
// 演示规范 // 演示规范
static PointList: PointListType = (params) => static PointList: PointListType = (params) =>
axios.post("malluser/muser/listMallUserPage", params); axios.post('malluser/muser/listMallUserPage', params);
// 积分列表-分页 // 积分列表-分页
static UserScorePageList: UserScorePageListType = (params) => static UserScorePageList: UserScorePageListType = (params) =>
axios.post("/uavscore/score/userScorePageList", params); axios.post('/uavscore/score/userScorePageList', params);
// 个人积分明细列表 // 个人积分明细列表
static UserScoreDetailsList: UserScoreDetailsListType = (params) => static UserScoreDetailsList: UserScoreDetailsListType = (params) =>
axios.post("/uavscore/score/userScoreDetailsList", params); axios.post('/uavscore/score/userScoreDetailsList', params);
// 个人积分明细--查看单条数据 // 个人积分明细--查看单条数据
static GetUserScoreDetails: GetUserScoreDetailsType = (params) => static GetUserScoreDetails: GetUserScoreDetailsType = (params) =>
axios.get("/uavscore/score/getUserScoreDetails", { params }); axios.get('/uavscore/score/getUserScoreDetails', { params });
// 流通方式列表 // 流通方式列表
static ListCirculateInfo: ListCirculateInfoType = (params) => static ListCirculateInfo: ListCirculateInfoType = (params) =>
axios.get("/uavscore/score/listCirculateInfo", { params }); axios.get('/uavscore/score/listCirculateInfo', { params });
// 积分发放 // 积分发放
static OrderScoreRelease: OrderScoreReleaseType = (params) => static OrderScoreRelease: OrderScoreReleaseType = (params) =>
axios.post("/uavscore/score/orderScoreRelease", params); axios.post('/uavscore/score/orderScoreRelease', params);
// 兑换规则--条件查询列表 // 兑换规则--条件查询列表
static ListConvertRule: ListConvertRuleType = (params) => static ListConvertRule: ListConvertRuleType = (params) =>
axios.get("/uavscore/score/listConvertRule", { params }); axios.get('/uavscore/score/listConvertRule', { params });
// 积分发放 // 积分发放
static AddConvertRule: AddConvertRuleType = (params) => static AddConvertRule: AddConvertRuleType = (params) =>
axios.post("/uavscore/score/addConvertRule", params); axios.post('/uavscore/score/addConvertRule', params);
// 积分提现审批 // 积分提现审批
static CheckUserScore: CheckUserScoreType = (params) => static CheckUserScore: CheckUserScoreType = (params) =>
axios.get("/uavscore/score/checkUserScore", { params }); axios.get('/uavscore/score/checkUserScore', { params });
// 获取指定明细列表 // 获取指定明细列表
static GetScoreList: GetScoreListType = (params) => static GetScoreList: GetScoreListType = (params) =>
axios.get("/uavscore/score/getScoreList", { params }); axios.get('/uavscore/score/getScoreList', { params });
// 根据订单编号查询订单 // 根据订单编号查询订单
static GetOrderInfoByOrderNo: GetOrderInfoByOrderNoType = (params) => static GetOrderInfoByOrderNo: GetOrderInfoByOrderNoType = (params) =>
axios.get("/mallorder/pmorderVerOne/getOrderInfoByOrderNo", { params }); axios.get('/mallorder/pmorderVerOne/getOrderInfoByOrderNo', { params });
// 积分管理-分成规则-列表查询 // 积分管理-分成规则-列表查询
static BonusRuleListQuery: BonusRuleListQueryType = (params) => static BonusRuleListQuery: BonusRuleListQueryType = (params) =>
axios.get("/uavscore/bonus/bonusRuleListQuery", { params }); axios.get('/uavscore/bonus/bonusRuleListQuery', { params });
// 积分管理-分成规则-分成对象列表 // 积分管理-分成规则-分成对象列表
static ListProportionObject: ListProportionObjectType = (params) => static ListProportionObject: ListProportionObjectType = (params) =>
axios.get("/uavscore/bonus/listProportionObject", { params }); axios.get('/uavscore/bonus/listProportionObject', { params });
// 积分管理-分成规则-分成对象新增/编辑 // 积分管理-分成规则-分成对象新增/编辑
static AddAndEditBonusRule: AddAndEditBonusRuleType = (params) => static AddAndEditBonusRule: AddAndEditBonusRuleType = (params) =>
axios.post("/uavscore/bonus/addAndEditBonusRule", params); axios.post('/uavscore/bonus/addAndEditBonusRule', params);
// 积分管理-分成规则-分成对象删除 // 积分管理-分成规则-分成对象删除
static RemoveBonusRule: RemoveBonusRuleType = (params) => static RemoveBonusRule: RemoveBonusRuleType = (params) =>
axios.get("/uavscore/bonus/removeBonusRule", { params }); axios.get('/uavscore/bonus/removeBonusRule', { params });
// 积分管理-订单分成-获取科比特员工标签的相关用户 // 积分管理-订单分成-获取科比特员工标签的相关用户
static ListKBTMallUser: ListKBTMallUserType = (params) => static ListKBTMallUser: ListKBTMallUserType = (params) =>
axios.get("/malluser/muser/listKBTMallUser", { params }); axios.get('/malluser/muser/listKBTMallUser', { params });
// 积分管理-订单分成-订单分成列表 // 积分管理-订单分成-订单分成列表
static OrderBonusListPage: OrderBonusListPageType = (params) => static OrderBonusListPage: OrderBonusListPageType = (params) =>
axios.post("/mallorder/orderBonus/listPage", params); axios.post('/mallorder/orderBonus/listPage', params);
// 积分管理-订单分成-规则-下拉列表 // 积分管理-订单分成-规则-下拉列表
static OrderBonusListRule: OrderBonusListRuleType = (params) => static OrderBonusListRule: OrderBonusListRuleType = (params) =>
axios.get("/uavscore/bonus/listRule", { params }); axios.get('/uavscore/bonus/listRule', { params });
// 积分管理-订单分成-订单分成详情 // 积分管理-订单分成-订单分成详情
static OrderBonusListByOrderId: OrderBonusListByOrderIdType = (params) => static OrderBonusListByOrderId: OrderBonusListByOrderIdType = (params) =>
axios.get("/mallorder/orderBonus/listByOrderId", { params }); axios.get('/mallorder/orderBonus/listByOrderId', { params });
// 积分管理-订单分成-根据规则id、订单id 计算分成对象积分 // 积分管理-订单分成-根据规则id、订单id 计算分成对象积分
static OrderBonusBuildMall: OrderBonusBuildMallType = (params) => static OrderBonusBuildMall: OrderBonusBuildMallType = (params) =>
axios.get("/mallorder/orderBonus/buildMallOrderBonus", { params }); axios.get('/mallorder/orderBonus/buildMallOrderBonus', { params });
// 积分管理-订单分成-无人机城账号管理-分页 // 积分管理-订单分成-无人机城账号管理-分页
static ListMallUserPage: ListMallUserPageType = (params) => static ListMallUserPage: ListMallUserPageType = (params) =>
axios.post("/malluser/muser/listMallUserPage", params); axios.post('/malluser/muser/listMallUserPage', params);
// 积分管理-订单分成-计算拓展规则分成对象 // 积分管理-订单分成-计算拓展规则分成对象
static CalculateOrderBonusVO: CalculateOrderBonusVOType = (params) => static CalculateOrderBonusVO: CalculateOrderBonusVOType = (params) =>
axios.post("/mallorder/orderBonus/calculateOrderBonusVO", params); axios.post('/mallorder/orderBonus/calculateOrderBonusVO', params);
// 积分管理-订单分成-修改分成对象 // 积分管理-订单分成-修改分成对象
static UpdateMallOrderBonus: UpdateMallOrderBonusType = (params) => static UpdateMallOrderBonus: UpdateMallOrderBonusType = (params) =>
axios.post("/mallorder/orderBonus/updateMallOrderBonus", params); axios.post('/mallorder/orderBonus/updateMallOrderBonus', params);
// 积分管理-订单分成-分页条件查找用户列表 // 积分管理-订单分成-分页条件查找用户列表
static MallUserBySearchKey: MallUserBySearchKeyType = (params) => static MallUserBySearchKey: MallUserBySearchKeyType = (params) =>
axios.get("/malluser/muser/mallUserBySearchKey", { params }); axios.get('/malluser/muser/mallUserBySearchKey', { params });
// 积分管理-订单分成-发放积分 // 积分管理-订单分成-发放积分
static DistributeMallOrderBonus: DistributeMallOrderBonusType = (params) => static DistributeMallOrderBonus: DistributeMallOrderBonusType = (params) =>
axios.get("/mallorder/orderBonus/distributeMallOrderBonus", { params }); axios.get('/mallorder/orderBonus/distributeMallOrderBonus', { params });
} }
...@@ -14,3 +14,9 @@ body { ...@@ -14,3 +14,9 @@ body {
min-height: 100vh; min-height: 100vh;
min-width: 100vw; min-width: 100vw;
} }
@font-face {
font-family: 'YouSheBiaoTiHei'; //重命名字体名
src: url('../font/title.ttf'); //引入字体
font-weight: normal;
font-style: normal;
}
import {Empty, theme} from "antd"; import { Empty, theme } from 'antd';
import React from "react"; import React from 'react';
export const themeConfig = { export const themeConfig = {
algorithm: [theme.compactAlgorithm], algorithm: [theme.compactAlgorithm],
...@@ -60,5 +60,5 @@ export const themeConfig = { ...@@ -60,5 +60,5 @@ export const themeConfig = {
}; };
// 空状态定制 // 空状态定制
export const renderEmpty = () => ( export const renderEmpty = () => (
<Empty description="暂无数据" image={Empty.PRESENTED_IMAGE_SIMPLE}/> <Empty description='暂无数据' image={Empty.PRESENTED_IMAGE_SIMPLE} />
); );
.navHeader {
width: 100%;
height: 68px;
background: linear-gradient(360deg, #002157 0%, #00102c 100%);
display: flex;
align-items: center;
justify-content: center;
}
.logo {
width: 148px;
height: 68px;
background-image: url(./assets/logo.png);
background-size: 100% 100%;
}
.tabs {
height: 100%;
margin-right: 58px;
:global .ant-tabs-nav {
height: 100%;
margin-bottom: 0;
&::before {
border: 0;
}
}
:global .ant-tabs-tab {
& + .ant-tabs-tab {
margin-left: 0px;
}
.ant-tabs-tab-btn {
font-size: 16px;
color: #fff;
width: 90px;
text-align: center;
font-family: MicrosoftYaHei;
}
}
:global .ant-tabs-tab-active {
.ant-tabs-tab-btn {
color: #91c8ff !important;
}
}
:global .ant-tabs-ink-bar {
display: none;
}
}
.btns {
margin-right: 25px;
}
.btn1 {
width: 120px;
height: 40px;
background: linear-gradient(90deg, #278eff 0%, #0052da 100%);
border-radius: 6px;
border: 0;
font-size: 16px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ffffff;
&:hover {
opacity: 0.8;
}
}
.btn2 {
box-sizing: border-box;
width: 120px;
height: 40px;
border-radius: 6px;
border: 1px solid #ffb02c;
font-size: 16px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ffb02c;
background: none;
}
.headImg {
width: 48px;
height: 48px;
background: #ffffff;
}
import React, { useState } from 'react';
import { Avatar, Button, Space, Tabs } from 'antd';
import type { TabsProps } from 'antd';
import styles from './index.module.scss';
import { useLocation, useNavigate } from 'react-router-dom';
const items: TabsProps['items'] = [
{
key: '/home',
label: ` 首页 `,
},
{
key: '1',
label: `作业服务`,
},
{
key: '2',
label: `设备租赁`,
},
{
key: '3',
label: `飞手服务`,
},
{
key: '/mall',
label: `产品商城`,
},
{
key: '5',
label: `项目资讯`,
},
{
key: '6',
label: `社区论坛`,
},
];
export default function NavHeader() {
const navigate = useNavigate();
const location = useLocation();
const currentPath = location.pathname;
console.log('currentHash', location);
const onChange = (key: string) => {
console.log(key);
navigate(key)
};
return (
<div className={styles.navHeader}>
<div className={styles.logo}></div>
<Tabs
className={styles.tabs}
defaultActiveKey={currentPath}
items={items}
onChange={onChange}
/>
<Space size={16} className={styles.btns}>
<Button type='primary' className={styles.btn1}>
+ 发布信息
</Button>
<Button className={styles.btn2}>入驻加盟</Button>
</Space>
<div className={styles.haedImg}>
<Avatar size={48} style={{ background: '#fff' }}></Avatar>
</div>
</div>
);
}
// 颜色变量
$color-primary: #f4b700;
$color-primary-hover: #f7c800;
$color-primary-active: #ffcc32;
$color-primary-border: #f4b700;
.brand-select-search-view {
position: relative;
width: 100%;
box-sizing: border-box;
.brand-select-item {
min-height: 50px;
background: #fff;
display: flex;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
position: relative;
padding: 12px 20px 12px 20px;
border-bottom: 1px solid #f2f4fa;
.item-label {
font-size: 14px;
color: #979aa8;
margin-right: 16px;
min-width: 32px;
}
.item-content {
display: flex;
align-items: center;
justify-content: flex-start;
flex-wrap: wrap;
width: 100%;
.alphabet-list, .select-list {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
margin-bottom: 10px;
flex-wrap: wrap;
.list-item {
position: relative;
height: 24px;
width: 20px;
font-size: 14px;
line-height: 20px;
margin: 0 16px 0 0;
border-radius: 2px;
text-align: center;
border: 1px solid transparent;
cursor: pointer;
user-select: none;
}
.list-item:hover {
color: $color-primary;
}
.list-item:hover:after {
position: absolute;
content: '';
width: 35%;
height: 1px;
background: $color-primary;
left: calc((100% - 35%) / 2);
bottom: 0;
}
.item-active {
background: $color-primary-active;
border: 1px solid $color-primary;
}
.item-active:hover {
color: #000000;
}
.item-active:hover:after {
display: none;
}
}
.select-list {
margin-bottom: 0;
.list-item {
width: 80px;
margin: 0 10px 0 0;
}
}
.selected {
margin-bottom: -10px;
.list-item {
border: 1px solid $color-primary;
color: $color-primary;
margin-bottom: 10px;
}
.list-item:hover {
background: #f7f8fc;
}
.list-item:hover:after {
display: none;
}
}
.alphabet-content {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
padding: 2px 12px 12px;
background-color: #f7f8fc;
width: 100%;
min-height: 50px;
box-sizing: border-box;
.content-item {
position: relative;
width: 80px;
margin: 10px 8px 0 0;
font-size: 14px;
overflow: hidden;
background: #ffffff;
text-align: center;
height: 28px;
line-height: 26px;
border: 1px solid transparent;
user-select: none;
}
.content-item:hover {
color: #f4b700;
}
.content-item:hover:after {
position: absolute;
content: '';
width: 35%;
height: 1px;
background: #f4b700;
left: calc((100% - 35%) / 2);
bottom: 0;
}
.item-active {
background: $color-primary-active;
border: 1px solid $color-primary;
}
.item-active:hover {
color: #000000;
}
.item-active:hover:after {
display: none;
}
}
.select-region {
.region-label {
margin: 0 12px;
}
.region-label:first-child{
margin-left: 0;
}
}
}
}
.brand-select-item:last-child {
border-bottom: none;
}
}
import React, { useEffect, useState } from 'react';
import './index.scss';
import { pinyin } from 'pinyin-pro';
import { Select } from 'antd';
// 搜索列表的类型
interface searchColumns {
type: 'Alphabet' | 'Brand' | 'Price' | 'Industry' | 'Product';
options: { label: string; value: any; children?: { label: string; value: any }[] }[];
name: string;
label: string;
subLabel?: string;
}
// 传参类型
interface propType {
columns: searchColumns[];
selected: boolean;
region: boolean;
}
const BrandSelectItem: React.FC<{ label: string; children: any }> = (props) => {
const { label, children } = props;
return (
<div className={'brand-select-item'}>
<div className={'item-label'}>{label}</div>
<div className={'item-content'}>{children}</div>
</div>
);
};
const BrandSelectSearch: React.FC<propType> = (props) => {
const { columns, selected, region } = props;
// 字母列表转换
const [alphabetList, setAlphabetList] = useState<{ label?: string; children: any }[]>([]);
// 字母列表索引
const [alphabetIndex, setAlphabetIndex] = useState<number>(0);
// 字母列表详情索引
const [alphabetContentIndex, setAlphabetContentIndex] = useState<number>(0);
// 普通筛选索引
const [optionsIndex, setOptionsIndex] = useState<{ index: number; subIndex?: number }[]>([]);
// 转换过后的普通筛选列表
const [columnsList, setColumnsList] = useState<searchColumns[]>([]);
// 获取字母列表 (将传入的列表转成以拼音开头的数组)
const getAlphabetList = () => {
// 如果没有字母列表则不执行
if (!columns.some((i) => i.type === 'Alphabet')) return;
// 获取字母列表
const options = columns.find((i) => i.type === 'Alphabet')?.options;
// 获取开头字母列表(去重)
const arr = [
...new Set(
options?.map((i) =>
pinyin(i.label, { toneType: 'none', type: 'array' })?.at(0)?.at(0)?.toUpperCase(),
),
),
].sort();
// 转换成展示列表
setAlphabetList(
arr?.map((i) => {
const children =
options?.filter(
(j) =>
pinyin(j.label, { toneType: 'none', type: 'array' })?.at(0)?.at(0)?.toUpperCase() ===
i,
) || [];
return {
label: i,
children: [{ label: '不限', value: 'all' }, ...children],
};
}),
);
};
// 获取普通列表
const getOptionsList = (options: { label: string; value: any }[]) => {
return [{ label: '不限', value: 'all' }, ...options];
};
// componentDidMount
useEffect(() => {
if (!columns) return;
getAlphabetList();
// 初始化索引
setOptionsIndex(columns.map((i) => (i.subLabel ? { index: 0, subIndex: 0 } : { index: 0 })));
// 初始化列表
setColumnsList(columns?.map((i) => ({ ...i, options: getOptionsList(i.options) })));
}, [columns]);
// componentDidUpdate
useEffect(() => {
// 如果没有普通筛选列表则不执行
if (!optionsIndex.length) return;
// 如果普通筛选列表全为0则不执行
if (!optionsIndex.some((i) => i.index !== 0)) return;
console.log('optionsIndex --->', optionsIndex);
console.log(
'componentDidUpdate -->',
optionsIndex.map((i, j) => columnsList[j].options[i.index]),
);
}, [optionsIndex]);
return (
<div className={'brand-select-search-view'}>
{region && (
<BrandSelectItem label={'地区'}>
<div className={'select-region'}>
<span className={'region-label'}></span>
<Select placeholder={'请选择省份'} options={[]} size={'small'} />
<span className={'region-label'}></span>
<Select placeholder={'请选择城市'} options={[]} size={'small'} />
</div>
</BrandSelectItem>
)}
{columnsList.map((i, j) => {
if (i.type === 'Alphabet') {
return (
<BrandSelectItem label={'品牌'} key={j}>
<div className='alphabet-list'>
{alphabetList.map((n, m) => (
<div
className={`list-item ${alphabetIndex === m && 'item-active'}`}
key={m}
onClick={() => {
setAlphabetIndex(m);
setAlphabetContentIndex(0);
}}
>
{n.label}
</div>
))}
</div>
<div className='alphabet-content'>
{alphabetList[alphabetIndex]?.children?.map((n: any, m: number) => (
<div
className={`content-item ${alphabetContentIndex === m && 'item-active'}`}
key={m}
onClick={() => {
setAlphabetContentIndex(alphabetContentIndex === m ? 0 : m);
const index =
columnsList
.find((i) => i.type === 'Alphabet')
?.options?.findIndex((i) => i.label === n.label) || 0;
// setOptionsIndex(optionsIndex?.map((i, k) => (k === j ? index : i)));
setOptionsIndex(optionsIndex?.map((i, k) => (k === j ? { index } : i)));
}}
>
{n.label}
</div>
))}
</div>
</BrandSelectItem>
);
}
if (['Industry', 'Brand', 'Price', 'Product'].includes(i.type)) {
return (
<div key={j}>
<BrandSelectItem label={i.label}>
<div className='select-list'>
{i.options?.map((n, m) => (
<div
className={`list-item ${optionsIndex[j].index === m && 'item-active'}`}
key={m}
onClick={() => {
setOptionsIndex(
optionsIndex.map((l, k) =>
k === j
? optionsIndex[j].index === m
? i.subLabel
? { index: 0, subIndex: 0 }
: { index: 0 }
: i.subLabel
? { index: m, subIndex: 0 }
: { index: m }
: l,
),
);
}}
>
{n.label}
</div>
))}
</div>
</BrandSelectItem>
{!!i.subLabel && (
<BrandSelectItem label={i.subLabel}>
<div className='select-list'>
{getOptionsList(i.options[optionsIndex[j].index]?.children || [])?.map(
(n, m) => (
<div
className={`list-item ${optionsIndex[j].subIndex === m && 'item-active'}`}
key={m}
onClick={() => {
setOptionsIndex(
optionsIndex.map((i, k) =>
k === j ? { ...i, subIndex: m === i.subIndex ? 0 : m } : i,
),
);
}}
>
{n.label}
</div>
),
)}
</div>
</BrandSelectItem>
)}
</div>
);
}
})}
{selected && (
<BrandSelectItem label={'已选'}>
<div className='select-list selected'>
{optionsIndex.map(
(n, m) =>
columnsList[m].options[n.index].label !== '不限' && (
<div
className={`list-item`}
key={m}
onClick={() => {
// setOptionsIndex(
// optionsIndex.map((i, k) => (k === j ? (optionsIndex[j] === m ? 0 : m) : i)),
// );
}}
>
{columnsList[m].options[n.index].label}
</div>
),
)}
</div>
</BrandSelectItem>
)}
</div>
);
};
export default BrandSelectSearch;
.footer {
height: 200px;
background: linear-gradient(360deg, #001c49 0%, #021741 100%);
box-shadow: 0px 2px 12px 0px rgba(146, 146, 146, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.logo {
width: 125px;
height: 89px;
background: url('./assets/logo.png') no-repeat;
background-size: 100% 100%;
margin-right: 104px;
}
.qrcodeList {
display: flex;
margin-right: 101px;
.qrcodeItem {
margin-right: 87px;
&:nth-last-child(1) {
margin-right: 0;
}
.qrcodeImg {
width: 100px;
height: 100px;
border-radius: 8px;
overflow: hidden;
background-color: #fff;
}
.qrcodeTitle {
margin-top: 12px;
font-size: 12px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ffffff;
text-align: center;
}
}
}
.rightText {
.number {
text-align: center;
font-size: 58px;
font-family: Arial-Black, Arial;
font-weight: 900;
color: RGBA(255, 176, 45, 1);
line-height: 82px;
}
.text {
font-size: 16px;
font-family: MicrosoftYaHei;
color: #fff;
line-height: 21px;
}
}
import styles from './index.module.scss';
const qrcodeList = [
{
img: '',
title: '科比特官网',
},
{
img: '',
title: '云享飞服务号',
},
{
img: '',
title: '云享飞小程序',
},
{
img: '',
title: '官方社群',
},
];
export default function Footer() {
return (
<div className={styles.footer}>
<div className={styles.logo}></div>
<div className={styles.qrcodeList}>
{
qrcodeList.map(item => {
return (
<div className={styles.qrcodeItem}>
<img className={styles.qrcodeImg} src={item.img}></img>
<div className={styles.qrcodeTitle}>{item.title}</div>
</div>
);
})
}
</div>
<div className={styles.rightText}>
<div className={styles.number}>100W</div>
<div className={styles.text}>无人机新媒体矩阵等你来关注</div>
</div>
</div>
);
}
import { useEffect, useState } from 'react';
import { Breadcrumb, Layout } from 'antd';
import { useLocation } from 'react-router-dom';
import { GetRouteByPath, getRouteParent } from '~/utils/router';
import { routerList } from '~/router/router';
import { ItemType } from 'antd/es/breadcrumb/Breadcrumb';
const { Header } = Layout;
function HeaderView() {
// 当前路由
const location = useLocation();
// 面包屑数据
const [header, setHeader] = useState<ItemType[]>([]);
// 根据路由获取当前的面包屑
const setBreadcrumbTitle = () => {
const pTitle = getRouteParent(routerList, location.pathname)?.meta.title;
const title = GetRouteByPath(location.pathname, routerList)?.meta.title;
setHeader([{ title: pTitle }, { title }]);
};
// componentDidMount
useEffect(() => {
setBreadcrumbTitle();
}, [location]);
return (
<Header>
<Breadcrumb items={header} />
</Header>
);
}
export default HeaderView;
$page-background: #F6F7FB;
.layout-view {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
.layout-bg{
background: $page-background;
}
.ant-layout-header {
background: $page-background;
box-sizing: border-box;
display: flex;
align-items: center;
height: 50px;
//.ant-breadcrumb-link {
// color: rgba(255, 255, 255, 0.68);
//}
//
//.ant-breadcrumb-separator {
// color: rgba(255, 255, 255, 0.68);
//}
//
//li:last-child {
// .ant-breadcrumb-link {
// color: #ffffff;
// }
//}
}
.ant-layout-sider::-webkit-scrollbar {
display: none;
}
.ant-layout-sider {
background-color: $page-background;
overflow: auto;
//height: calc(100vh - 44px);
left: 0;
top: 0;
bottom: 48px;
.ant-menu-dark {
background: transparent;
//font-size: 14px;
}
.ant-menu-item {
transform: translateX(10px);
.ant-menu-item-icon {
transform: translateX(-10px);
}
.ant-menu-title-content {
transform: translateX(-10px);
}
}
.ant-menu-item-selected,
.ant-menu-item,
.ant-menu-submenu-title {
height: 44px;
margin-top: 2px;
margin-bottom: 2px;
}
.ant-menu-item-selected {
//background: #1a232c;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.sider-collapsed {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 40px;
//background: #000c17;
display: flex;
align-items: center;
justify-content: center;
border: none;
padding: 0;
.collapsed-icon {
color: #ffffff;
}
}
}
:where(.css-dev-only-do-not-override-1os3dla).ant-menu-dark.ant-menu-inline
.ant-menu-sub.ant-menu-inline {
background: none;
}
.layout-logo {
height: 100%;
//width: 170px;
display: flex;
justify-content: space-between;
align-items: center;
.logo-img {
width: 32px;
height: 32px;
}
.logo-text {
font-size: 18px;
//color: #ffffff;
text-align: center;
animation: fadeIn 0.618s ease-in-out;
animation-fill-mode: forwards;
font-family: YouSheBiaoTiHei;
margin: 0 15px;
}
}
.layout-logo:hover {
filter: brightness(0.86);
cursor: pointer;
}
.title-user {
position: absolute;
right: 0;
top: 0;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.current-project {
display: flex;
align-items: center;
padding-right: 20px;
.project-label {
padding-right: 5px;
}
}
.user-content {
line-height: normal;
margin-right: 10px;
text-align: left;
.user-company {
font-size: 12px;
font-weight: 600;
//color: #ffffff;
}
.user-name {
font-size: 12px;
font-weight: normal;
color: #7f828a;
}
}
.user-action {
margin-right: 10px;
width: 24px;
height: 24px;
border:1px solid #3a4252;
border-radius: 2px;
padding: 0;
line-height: normal;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
}
.ant-layout-header {
padding: 0 10px;
}
.ant-layout-sider-collapsed {
.layout-logo {
padding: 0;
}
.logo-text {
display: none;
}
}
.layout-content {
//padding: 24px 32px 0px;
padding: 10px 15px;
overflow: auto;
background-color: #ffffff;
border-radius: 10px;
//color: #ffffff;
margin: 0 10px 10px 0;
box-sizing: border-box;
position: relative;
box-shadow: 0 16px 24px 0 #eeeeee;
}
.layout-content::-webkit-scrollbar {
background-color: transparent;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius: 2em;
width: 7px;
height: 7px;
}
.layout-content::-webkit-scrollbar-thumb {
background-color: #0878df;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius: 2em;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
}
import React, { Suspense } from 'react'; import { Layout } from 'antd';
import { Layout, Space } from 'antd';
import { Outlet } from 'react-router-dom'; import { Outlet } from 'react-router-dom';
import NavHeader from '~/components/NavHeader'; // eslint-disable-next-line import/no-cycle
import FooterView from '~/components/footer'; import HeaderView from './header';
import { MenuView } from './menu';
import './index.scss';
import { TitleView } from './title';
const { Header, Footer, Content } = Layout; const { Content } = Layout;
function LayoutView() {
const headerStyle: React.CSSProperties = {
height: 'auto',
background: 'none',
padding: 0,
lineHeight: '1',
position: 'relative'
};
const contentStyle: React.CSSProperties = {
minHeight: 120,
lineHeight: '1',
color: '',
backgroundColor: '',
position: 'relative',
};
const footerStyle: React.CSSProperties = {
color: '',
backgroundColor: '',
lineHeight: '1',
padding: 0,
position: 'relative'
};
type Props = {
children: React.ReactNode;
};
export default function LayoutView(props: Props) {
return ( return (
<Space direction='vertical' style={{ width: '100%' }} size={[0, 48]}> <Layout className='layout-view'>
<Layout style={{ minHeight: '100vh' }}> <TitleView />
<Header style={headerStyle}> <Layout>
<NavHeader /> <MenuView />
</Header> <Layout className='layout-bg'>
<Content style={contentStyle}> <HeaderView />
{props.children} <Content className='layout-content'>
<Suspense fallback={<div>Loading...</div>}> <Outlet />
<Outlet></Outlet>
</Suspense>
</Content> </Content>
<Footer style={footerStyle}>
<FooterView></FooterView>
</Footer>
</Layout> </Layout>
</Space> </Layout>
</Layout>
); );
} }
export default LayoutView;
import { useEffect, useState } from 'react';
import type { MenuProps } from 'antd';
import { Layout, Menu } from 'antd';
import { RouteObjectType, routerList } from '~/router/router';
import { useLocation, useNavigate } from 'react-router-dom';
import { GetRouteByID, getRouteID, getRoutePid } from '~/utils/router';
type MenuItem = Required<MenuProps>['items'][number];
const { Sider } = Layout;
export function MenuView() {
// 菜单路由列表
const [items, setItems] = useState<MenuItem[]>([]);
// 当选选中的项目
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
// 当选选中的项目的subMenu
const [openKeys, setOpenKeys] = useState<string[]>([]);
// 路由钩子
const location = useLocation();
// 路由跳转钩子
const navigate = useNavigate();
// 点击侧边栏事件
const onOpenChange: MenuProps['onOpenChange'] = (keys) => {
setOpenKeys(keys);
// console.log('侧边栏事件 -->', keys);
};
// 点击侧边栏事件
const onSelect: MenuProps['onSelect'] = (keys) => {
setSelectedKeys(keys.selectedKeys);
const id = Number(keys.key);
const current = GetRouteByID(id, routerList);
// console.log(current?.path);
if (current) navigate(current?.path);
};
// 递归将路由转换为侧边栏数据
const getItem = (routerList: RouteObjectType[]) => {
const list: MenuItem[] = routerList.map((i) => {
if (i.children?.length) {
return {
label: i.meta?.title,
key: i.meta?.id,
icon: i.meta?.icon,
children: getItem(i.children || []),
};
} else {
return {
label: i.meta?.title,
key: i.meta?.id,
icon: i.meta?.icon,
};
}
});
return list;
};
// 组件挂载
useEffect(() => {
// 设置侧边栏数据
setItems(getItem(routerList));
// 设置当前选中的项目
setOpenKeys([getRoutePid(routerList, location.pathname).toString()]);
// 设置当前选中的项目的subMenu
setSelectedKeys([getRouteID(routerList, location.pathname).toString()]);
}, []);
return (
<Sider style={{ paddingTop: '50px' }} collapsible collapsed={false} width={180} trigger={null}>
<Menu
openKeys={openKeys}
selectedKeys={selectedKeys}
onSelect={onSelect}
onOpenChange={onOpenChange}
mode='inline'
items={items}
/>
{/* <div className="sider-collapsed" onClick={() => setCollapsed(!collapsed)}> */}
{/* <Button */}
{/* className="collapsed-icon" */}
{/* type="link" */}
{/* icon={collapsed ? <RightOutlined /> : <LeftOutlined />} */}
{/* /> */}
{/* </div> */}
</Sider>
);
}
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
fill: currentColor;
transform: translateY(-3px);
//color: #fff;
}
.hamburger.is-active {
transform: rotate(180deg) translateY(3px);
}
.effective{
.ant-btn-default{
// display: none;
background-color: #1677ff !important;
&:hover {
background-color: #4893fd !important;
}
}
.ant-btn-primary{
display: none;
}
}
import React, { useState } from 'react';
import { Header } from 'antd/es/layout/layout';
import { DownOutlined, UpOutlined } from '@ant-design/icons';
import { Button, Dropdown, MenuProps, Modal } from 'antd';
import Logo from '../../../assets/icon/logo.svg';
import './index.scss';
export function TitleView() {
const { confirm } = Modal;
// 菜单栏是否收起
const [isActive, setIsActive] = useState(false);
// 菜单栏收起
const setMenuCollapsed = () => {
setIsActive(!isActive);
};
// 右上角按钮
const items: MenuProps['items'] = [
{
key: '1',
label: (
<Button
type='link'
onClick={() => {
confirm({
title: '退出登录',
content: '退出后未保存数据将会丢失,确定登出吗?',
onOk: () => {
console.log('点击');
},
});
}}
>
退出登录
</Button>
),
},
];
return (
<Header
style={{
background: '#ffffff',
height: 40,
padding: '0 10px',
position: 'relative',
}}
>
<div className='layout-logo'>
<img className='logo-img' src={Logo} alt='云享飞' />
<div className='logo-text'>云享飞后台管理</div>
<div onClick={setMenuCollapsed}>
<svg
className={`hamburger ${isActive ? 'is-active' : ''}`}
viewBox='0 0 1024 1024'
xmlns='http://www.w3.org/2000/svg'
width='64'
height='64'
>
<path d='M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z' />
</svg>
</div>
</div>
<div className='title-user'>
<div className='user-content'>
<div className='user-company'>科比特</div>
<div className='user-name'>admin</div>
</div>
<Dropdown
overlayStyle={{ textAlign: 'center' }}
menu={{ items }}
placement='bottomRight'
arrow
>
<div className='user-action'>
<UpOutlined style={{ fontSize: 10, color: '#8287A0' }} />
<DownOutlined style={{ fontSize: 10, color: '#8287A0' }} />
</div>
</Dropdown>
</div>
</Header>
);
}
.uploader-view{ .uploader-view {
.ant-upload-wrapper .ant-upload-list .ant-upload-list-item-container{ .ant-upload-wrapper .ant-upload-list .ant-upload-list-item-container {
//width: 200px !important; //width: 200px !important;
} }
} }
...@@ -16,7 +16,7 @@ const root = ReactDOM.createRoot(document.getElementById('root')!); ...@@ -16,7 +16,7 @@ const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render( root.render(
// <React.StrictMode> // <React.StrictMode>
<ConfigProvider locale={zhCN} theme={themeConfig} > <ConfigProvider locale={zhCN} theme={themeConfig}>
<App /> <App />
</ConfigProvider>, </ConfigProvider>,
// </React.StrictMode>, // </React.StrictMode>,
......
import React from 'react';
export default function Home() {
return (
<div>123</div>
)
}
import React from 'react';
export default function JobServices() {
return <div>JobServices</div>;
}
.productList {
.title {
padding: 20px 10px 18px;
text-align: left;
}
.main {
display: flex;
.ad {
flex-shrink: 0;
width: 260px;
height: 420px;
margin-left: 16px;
background-color: gray;
}
}
.listWrap {
display: flex;
flex-wrap: wrap;
margin-left: -14px;
.item {
width: 220px;
height: 326px;
background: #ffffff;
border-radius: 6px;
margin-bottom: 15px;
display: flex;
flex-direction: column;
justify-content: space-between;
padding-bottom: 18px;
margin-left: 14px;
.img {
width: 100%;
height: 220px;
}
.title {
padding: 0 18px;
font-size: 15px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 24px;
height: 48px;
display: -webkit-box; /* 使用弹性盒子布局 */
-webkit-line-clamp: 2; /* 显示行数 */
-webkit-box-orient: vertical; /* 垂直排列 */
overflow: hidden; /* 隐藏溢出部分 */
text-overflow: ellipsis; /* 使用省略号代替溢出部分 */
}
.sellCount {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #ff552d;
padding-left: 20px;
}
}
}
}
\ No newline at end of file
import React, { useEffect, useState } from 'react';
import { Button, Select, Space, Tag } from 'antd';
import styles from './index.module.scss';
export default function Mall() {
const [productList, setProductList] = useState(Array<{}>);
useEffect(() => {
setProductList([{}, {}, {}, {}, {}, {}]);
}, [])
const onProvinceChange = (value: string) => {
console.log('省', value);
};
const onCityChange = (value: string) => {
console.log('市', value);
};
const onMoreChange = (value: string) => {
console.log('更多', value);
};
const onCloseTag = (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
console.log('删除', e);
};
return (
<div className='page' style={{ paddingTop: '29px' }}>
<div className='filter-wrap' style={{ marginBottom: '11px' }}>
<div className='filter-item'>
<div className='filter-item__title'>地域:</div>
<div className='filter-item-main'>
<Space size={40}>
<Select
bordered={false}
dropdownMatchSelectWidth={false}
placeholder='选择省'
onChange={onProvinceChange}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
<Select
bordered={false}
dropdownMatchSelectWidth={false}
placeholder='选择市'
onChange={onCityChange}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
</Space>
</div>
</div>
</div>
<div className='filter-wrap'>
<div className='filter-item'>
<div className='filter-item__title'>类目:</div>
<div className='filter-item-main'>
<Space size={40}>
<Button type='link'>不限</Button>
<Button type='link'>无人机</Button>
<Button type='link'>挂载</Button>
<Button type='link'>地面站</Button>
</Space>
<Select
placeholder='更多'
onChange={onMoreChange}
bordered={false}
dropdownMatchSelectWidth={false}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
</div>
</div>
<div className='filter-item'>
<div className='filter-item__title'>品牌:</div>
<div className='filter-item-main'>
<Space size={40}>
<Button type='link'>不限</Button>
<Button type='link'>无人机</Button>
<Button type='link'>挂载</Button>
<Button type='link'>地面站</Button>
</Space>
<Select
placeholder='更多'
onChange={onMoreChange}
bordered={false}
dropdownMatchSelectWidth={false}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
</div>
</div>
<div className='filter-item'>
<div className='filter-item__title'>部件:</div>
<div className='filter-item-main'>
<Space size={40}>
<Button type='link'>不限</Button>
<Button type='link'>无人机</Button>
<Button type='link'>挂载</Button>
<Button type='link'>地面站</Button>
</Space>
<Select
placeholder='更多'
onChange={onMoreChange}
bordered={false}
dropdownMatchSelectWidth={false}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
</div>
</div>
<div className='filter-item'>
<div className='filter-item__title'>型号:</div>
<div className='filter-item-main'>
<Space size={40}>
<Button type='link'>不限</Button>
<Button type='link'>无人机</Button>
<Button type='link'>挂载</Button>
<Button type='link'>地面站</Button>
</Space>
<Select
placeholder='更多'
onChange={onMoreChange}
bordered={false}
dropdownMatchSelectWidth={false}
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
{ value: 'Yiminghe', label: 'yiminghe' },
{ value: 'disabled', label: 'Disabled', disabled: true },
]}
/>
</div>
</div>
<div className='filter-item'>
<div className='filter-item__title'>成色:</div>
<div className='filter-item-main'>
<Space size={40}>
<Button type='link'>不限</Button>
<Button type='link'>无人机</Button>
<Button type='link'>挂载</Button>
<Button type='link'>地面站</Button>
</Space>
</div>
</div>
<div className='filter-item'>
<div className='filter-item__title'>已选:</div>
<div className='filter-item-main'>
<Space size={10}>
<Tag closable onClose={onCloseTag}>
无人机
</Tag>
<Tag closable onClose={onCloseTag}>
无人机
</Tag>
</Space>
</div>
</div>
</div>
<div className={styles.productList}>
<div className={styles.title}>四旋翼无人机</div>
<div className={styles.main}>
<ul className={styles.listWrap}>
{
productList.map(item => {
return (
<li className={styles.item}>
<img className={styles.img}></img>
<div className={styles.title}>入云龙ll 1550入云龙ll 1550入云龙ll 1550入云龙ll 1550</div>
<div className={styles.sellCount}>半年售12987</div>
</li>
)
})
}
</ul>
<div className={styles.ad}>
</div>
</div>
</div>
</div>
);
}
import React from 'react';
function EquipmentOrderView() {
return <div>EquipmentOrderView</div>;
}
export default EquipmentOrderView;
import React from 'react';
function ProductOrderView() {
return <div>ProductOrderView</div>;
}
export default ProductOrderView;
import React from 'react';
function ServiceOrderView() {
return <div>ServiceOrderView</div>;
}
export default ServiceOrderView;
import { createHashRouter } from 'react-router-dom'; import { createBrowserRouter, RouteObject } from 'react-router-dom';
import { routerList } from '~/router/router'; import { RouteObjectType, routes } from '~/router/router';
// 导出路由表 // 导出路由表
export const router = createHashRouter(routerList); export const router = createBrowserRouter(routes);
// 路由表类型 // 路由表类型
// export type { routerItem } from "./router"; export type routerItem = RouteObject & RouteObjectType;
...@@ -2,44 +2,95 @@ import React from 'react'; ...@@ -2,44 +2,95 @@ import React from 'react';
import { Navigate, RouteObject } from 'react-router-dom'; import { Navigate, RouteObject } from 'react-router-dom';
import ErrorPage from '~/pages/common/error'; import ErrorPage from '~/pages/common/error';
import LayoutView from '~/components/layout'; import LayoutView from '~/components/layout';
import { MacCommandOutlined } from '@ant-design/icons';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { AgnosticIndexRouteObject } from '@remix-run/router';
import { Spin } from 'antd';
const Home = React.lazy(() => import('~/pages/home')); //首页 const ProductOrderView = React.lazy(() => import('src/pages/orderManage/productOrder')); //销售订单
const JobServices = React.lazy(() => import('~/pages/jobServices')); //工作服务 const EquipmentOrderView = React.lazy(() => import('src/pages/orderManage/equipmentOrder')); //设备订单
const Mall = React.lazy(() => import('~/pages/mall')); //产品商城 const ServiceOrderView = React.lazy(() => import('src/pages/orderManage/serviceOrder')); //服务订单
interface RouteObjectType { export interface RouteObjectType {
meta?: { path?: AgnosticIndexRouteObject['path'];
element?: React.ReactNode | null;
errorElement?: React.ReactNode | null;
children?: Array<RouteObject & RouteObjectType>;
meta: {
id: number; id: number;
hidden?: boolean; hidden?: boolean;
icon?: any; icon: any;
customIcon?: boolean; customIcon?: boolean;
title: string; title: string;
}; };
} }
const withLoadingComponent = (comp: JSX.Element) => (
<React.Suspense
fallback={
<Spin size='large' tip='Loading...'>
<div style={{ width: '100%', height: '50vh', marginTop: '10vh' }}></div>
</Spin>
}
>
{comp}
</React.Suspense>
);
// 路由数组 // 路由数组
export const routerList: Array<RouteObject & RouteObjectType> = [ export const routerList: Array<RouteObjectType> = [
{ {
path: '*', path: '/orderManage',
element: <div>404</div>, element: <LayoutView />,
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
meta: {
id: 10000,
icon: <MacCommandOutlined />,
title: '订单管理',
}, },
{
path: '/',
element: <LayoutView>{location.hash === '#/' && <Navigate to='/home' />}</LayoutView>,
errorElement: <ErrorPage />,
children: [ children: [
{ {
path: '/home', path: '/orderManage/productOrder',
element: <Home />, element: withLoadingComponent(<ProductOrderView />),
meta: {
id: 10010,
title: '销售订单',
icon: <MacCommandOutlined />,
},
}, },
{ {
path: '/jobServices', path: '/orderManage/equipmentOrder',
element: <JobServices />, element: withLoadingComponent(<EquipmentOrderView />),
meta: {
id: 10020,
title: '设备订单',
icon: <MacCommandOutlined />,
},
}, },
{ {
path: '/mall', path: '/orderManage/serviceOrder',
element: <Mall />, element: withLoadingComponent(<ServiceOrderView />),
meta: {
id: 10030,
title: '服务订单',
icon: <MacCommandOutlined />,
},
}, },
], ],
}, },
]; ];
// 路由白名单
export const whiteRouterList: Array<RouteObject & RouteObjectType> = [
{
path: '/',
element: <Navigate to='/orderManage/productOrder' />,
meta: {
id: 0,
title: '销售订单',
icon: MacCommandOutlined,
},
},
];
// 整合路由数据
export const routes = [...routerList, ...whiteRouterList];
...@@ -20,11 +20,10 @@ body::-webkit-scrollbar { ...@@ -20,11 +20,10 @@ body::-webkit-scrollbar {
background: #ffffff; background: #ffffff;
border-radius: 6px; border-radius: 6px;
*{ * {
font-size: 14px !important; font-size: 14px !important;
} }
.filter-item { .filter-item {
padding: 11px 0; padding: 11px 0;
border-bottom: 1px dashed RGBA(222, 222, 222, 1); border-bottom: 1px dashed RGBA(222, 222, 222, 1);
......
...@@ -3,19 +3,87 @@ ...@@ -3,19 +3,87 @@
License: none (public domain) License: none (public domain)
*/ */
html, body, div, span, applet, object, iframe, html,
h1, h2, h3, h4, h5, h6, p, blockquote, pre, body,
a, abbr, acronym, address, big, cite, code, div,
del, dfn, em, img, ins, kbd, q, s, samp, span,
small, strike, strong, sub, sup, tt, var, applet,
b, u, i, center, object,
dl, dt, dd, ol, ul, li, iframe,
fieldset, form, label, legend, h1,
table, caption, tbody, tfoot, thead, tr, th, td, h2,
article, aside, canvas, details, embed, h3,
figure, figcaption, footer, header, hgroup, h4,
menu, nav, output, ruby, section, summary, h5,
time, mark, audio, video { h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
...@@ -24,21 +92,34 @@ time, mark, audio, video { ...@@ -24,21 +92,34 @@ time, mark, audio, video {
vertical-align: baseline; vertical-align: baseline;
} }
/* HTML5 display-role reset for older browsers */ /* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, article,
footer, header, hgroup, menu, nav, section { aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block; display: block;
} }
body { body {
line-height: 1; line-height: 1;
} }
ol, ul { ol,
ul {
list-style: none; list-style: none;
} }
blockquote, q { blockquote,
q {
quotes: none; quotes: none;
} }
blockquote:before, blockquote:after, blockquote:before,
q:before, q:after { blockquote:after,
q:before,
q:after {
content: ''; content: '';
content: none; content: none;
} }
......
// import { useDispatch } from "react-redux";
// import { message } from 'antd';
import type { routerItem } from '~/router';
import { RouteObjectType } from '~/router/router';
// import { versionMenuEntity } from '../api/modules/superManage/interface';
// 菜单栏类型
export interface menuItem {
children: menuItem[];
domType: string;
icon: never;
id: number;
menuName: string;
pathInfo: never;
pid: number;
}
// 遍历路由树形结构
const getRouteList = (router: routerItem[]) => {
const list = router;
const arr: routerItem[] = [];
const getRoute = (item: routerItem) => {
arr.push(item);
if (item.children) {
item.children.map((i: routerItem) => {
getRoute(i);
});
}
};
if (list.length) {
list.map((i: routerItem) => {
getRoute(i);
});
}
return arr;
};
// 根据路由地址获取当前路由的id
export const getRouteID = (routerList: RouteObjectType[], path: string) => {
let id: number | string = '';
routerList.forEach((i) => {
if (i.path === path) {
id = i.meta?.id || '';
} else if (i.children?.length) {
id = getRouteID(i.children, path);
}
});
return id;
};
// 根据路由地址获取当前路由的父路由id
export const getRoutePid = (routerList: RouteObjectType[], path: string) => {
const item = routerList.find((v) => v.children && v.children.some((item) => item.path === path));
return item?.meta.id || '';
};
// 根据路由地址获取当前路由的父路由
export const getRouteParent = (routerList: RouteObjectType[], path: string) => {
const item = routerList.find((v) => v.children && v.children.some((item) => item.path === path));
return item;
};
// 通过path查询路由
export const GetRouteByPath = (path: string, router: routerItem[]) => {
const arr = getRouteList(router);
return arr.find((i) => i.path === path);
};
// 通过path查询路由
export const GetRouteByID = (id: number, router: routerItem[]) => {
const arr = getRouteList(router);
return arr.find((i) => i.meta.id === id);
};
//
// // 通过id查找当前展开的父项
// export const GetRoutePidByID = (id: number, menuList: routerItem[]) => {
// try {
// return menuList.find(
// (v: routerItem) =>
// (v.children && v.children.some((item: routerItem) => item.meta.id === id)) ||
// (v.btns && v.btns.some((item: routerItem) => item.meta.id === id)),
// );
// } catch (e) {
// // 判错冗余处理
// localStorage.setItem('TMJ-ADMIN-MENU-LIST', JSON.stringify([]));
// window.location.href = `${window.location.origin}/#/login`;
// message.error('出错了,请重新登录!').then();
// return { meta: { id: 1000, title: '首页' } };
// }
// };
//
// // 获取当前用户所有可用的id列表
// export const GetRouteIDList = (list: routerItem[]) => {
// const arr: number[] = []; // 全部可用的ID
// // 递归生成所有可用路由的id
// const getID = (item: routerItem) => {
// arr.push(item.meta.id);
// if (item.children) {
// item.children.map((i) => {
// getID(i);
// });
// }
// if (item.btns) {
// item.btns.map((i) => {
// getID(i);
// });
// }
// };
// if (list.length) {
// list.map((i: routerItem) => {
// getID(i);
// });
// }
// return arr;
// };
// 过滤路由
export const filterRouter = (list: routerItem[], ids: number[]) => {
return list.reduce((pre: any, cur: any) => {
const obj = { ...cur };
const bool: boolean = ids.some((v: number) => v === obj.meta.id);
if (bool) {
if (obj.children) {
obj.children = filterRouter(obj.children, ids);
}
pre.push(obj);
}
return pre;
}, []);
};
// 路由是否存在
export const isRoute = (list: any, pathname: string) => {
return list.some(
(v: any) => v.path === pathname || (v.children && isRoute(v.children, pathname)),
);
};
// 根据路由表获取可用的叶子节点
export const getLeafRoute = (ids: number[], list: any) => {
return list.reduce((pre: any, cur: any) => {
const bol: boolean = ids.some((id: number) => id === cur.meta.id);
if (bol && cur.children) {
pre.push(...getLeafRoute(ids, cur.children));
}
if (bol && !cur.children) {
pre.push(cur);
}
return pre;
}, []);
};
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论